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, index_to_meta},
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.contains(idx)
107 &&& valid_frame_paddr(pa)
108 &&& perm.slot_owners[idx].ref_count() > 0
109 &&& perm.slot_owners[idx].ref_count() + 1 < REF_COUNT_MAX
110 &&& !MetaSlot::inc_ref_count_panic_cond(perm.slot_owners[idx].ref_count_perm)
111 }
112 }
113
114 open spec fn clone_ensures(
115 self,
116 old_perm: MetaRegionOwners,
117 new_perm: MetaRegionOwners,
118 res: Self,
119 ) -> bool {
120 &&& res.range() == self.range()
121 &&& res.inv()
122 &&& new_perm.inv()
123 &&& new_perm.frame_obligations =~= old_perm.frame_obligations
128 }
129
130 #[verifier::loop_isolation(false)]
131 fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self) {
132 let mut paddr = self.range.start;
133
134 loop
135 invariant
136 perm.inv(),
137 self.inv(),
138 perm.slots == old(perm).slots,
139 perm.slot_owners.dom() == old(perm).slot_owners.dom(),
140 perm.frame_obligations == old(perm).frame_obligations,
141 self.range.start <= paddr <= self.range.end,
142 paddr % PAGE_SIZE == 0,
143 paddr <= MAX_PADDR,
144 forall|pa: Paddr|
145 #![trigger frame_to_index(pa)]
146 (paddr <= pa < self.range.end && pa % PAGE_SIZE == 0) ==> {
147 let idx = frame_to_index(pa);
148 &&& perm.contains(idx)
149 &&& valid_frame_paddr(pa)
150 &&& perm.slot_owners[idx].ref_count() > 0
151 &&& perm.slot_owners[idx].ref_count() + 1 < REF_COUNT_MAX
152 &&& !MetaSlot::inc_ref_count_panic_cond(
153 perm.slot_owners[idx].ref_count_perm,
154 )
155 },
156 decreases self.range.end - paddr,
157 {
158 if paddr >= self.range.end {
159 break;
160 }
161 unsafe {
162 #[verus_spec(with Tracked(perm))]
163 crate::mm::frame::inc_frame_ref_count(paddr)
164 };
165
166 paddr = paddr + PAGE_SIZE;
167 }
168
169 Self { range: self.range.start..self.range.end, _marker: core::marker::PhantomData }
170 }
171}
172
173#[verus_verify]
174impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Segment<M> {
175 #[verus_spec(r =>
207 with
208 Tracked(regions): Tracked<&mut MetaRegionOwners>,
209 Tracked(repr_perm): Tracked<&mut M::ReprPerm>,
210 requires
211 old(regions).inv(),
212 forall|paddr_in: Paddr|
213 (range.start <= paddr_in < range.end && paddr_in % PAGE_SIZE == 0) ==> {
214 &&& metadata_fn.requires((paddr_in,))
215 },
216 forall|paddr_in: Paddr, paddr_out: Paddr, m: M|
217 metadata_fn.ensures((paddr_in,), (paddr_out, m)) ==> paddr_in == paddr_out,
218 !(range.end <= MAX_PADDR ==> range.start < range.end) ==> may_panic(),
219 ensures
220 final(regions).inv(),
221 r is Err ==> final(regions).frame_obligations == old(regions).frame_obligations,
222 (range.start % PAGE_SIZE != 0 || range.end % PAGE_SIZE != 0)
223 ==> r == Err::<Self, _>(GetFrameError::NotAligned),
224 (range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0 && range.end > MAX_PADDR)
225 ==> r == Err::<Self, _>(GetFrameError::OutOfBound),
226 r matches Ok(seg) ==> {
227 &&& seg.start_paddr() == range.start
228 &&& seg.end_paddr() == range.end
229 &&& seg.start_paddr() < seg.end_paddr()
230 &&& seg.invariants(*final(regions))
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 &&& forall|paddr: Paddr|
238 #![trigger frame_to_index(paddr)]
239 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
240 ==> final(regions).contains(frame_to_index(paddr))
241 &&& range.start < range.end <= MAX_PADDR
242 },
243 )]
244 pub fn from_unused(range: Range<Paddr>, metadata_fn: impl Fn(Paddr) -> (Paddr, M)) -> (res:
245 Result<Self, GetFrameError>) {
246 proof_decl! {
247 let tracked mut addrs = Seq::<usize>::tracked_empty();
248 }
249
250 if range.start % PAGE_SIZE != 0 || range.end % PAGE_SIZE != 0 {
251 return Err(GetFrameError::NotAligned);
252 }
253 if range.end > MAX_PADDR {
254 return Err(GetFrameError::OutOfBound);
255 }
256 assert!(range.start < range.end);
257
258 let mut segment = Self {
259 range: range.start..range.start,
260 _marker: core::marker::PhantomData,
261 };
262
263 let mut i = 0;
264 let addr_len = (range.end - range.start) / PAGE_SIZE;
265
266 while i < addr_len
267 invariant
268 i <= addr_len,
269 i == addrs.len(),
270 range.start % PAGE_SIZE == 0,
271 range.end % PAGE_SIZE == 0,
272 range.end <= MAX_PADDR,
273 range.start <= range.start + i * PAGE_SIZE <= range.end,
274 range.end == range.start + addr_len * PAGE_SIZE,
275 addr_len == (range.end - range.start) / PAGE_SIZE as int,
276 i <= addr_len,
277 forall|paddr_in: Paddr|
278 (range.start + i * PAGE_SIZE <= paddr_in < range.end && paddr_in % PAGE_SIZE
279 == 0) ==> {
280 &&& metadata_fn.requires((paddr_in,))
281 },
282 forall|paddr_in: Paddr, paddr_out: Paddr, m: M|
283 range.start + i * PAGE_SIZE <= paddr_in < range.end && paddr_in % PAGE_SIZE == 0
284 && metadata_fn.ensures((paddr_in,), (paddr_out, m)) ==> paddr_in
285 == paddr_out,
286 forall|j: int|
287 #![trigger addrs[j]]
288 0 <= j < addrs.len() ==> {
289 let idx = frame_to_index(addrs[j]);
290 &&& regions.contains(idx)
291 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
292 &&& regions.slot_owners[idx].ref_count() > 0
293 &&& regions.slot_owners[idx].ref_count() <= REF_COUNT_MAX
294 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
295 &&& regions.slot_owners[idx].usage is Frame
296 &&& addrs[j] % PAGE_SIZE == 0
297 &&& addrs[j] < MAX_PADDR
298 &&& addrs[j] == range.start + (j as u64) * PAGE_SIZE
299 },
300 regions.inv(),
301 regions.frame_obligations == old(regions).frame_obligations,
302 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
303 segment.range.start == range.start,
304 segment.range.end == range.start + i * PAGE_SIZE,
305 ensures
306 i == addr_len,
307 decreases addr_len - i,
308 {
309 let paddr_in = range.start + i * PAGE_SIZE;
310 let (paddr, meta) = metadata_fn(paddr_in);
311
312 let ghost regions_pre = *regions;
313 let res = #[verus_spec(with Tracked(regions), Tracked(repr_perm))]
314 Frame::<M>::from_unused(paddr, meta);
315 let frame = match res {
316 Ok(f) => f,
317 Err(e) => {
318 let mut p = range.start;
319 let ghost mut k: int = 0;
320 while p < segment.range.end
321 invariant
322 regions.inv(),
323 regions.frame_obligations == old(regions).frame_obligations,
324 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
325 range.start % PAGE_SIZE == 0,
326 i == addrs.len(),
327 segment.range.end == range.start + i * PAGE_SIZE,
328 segment.range.end <= MAX_PADDR,
329 range.start <= p <= segment.range.end,
330 p == range.start + k * PAGE_SIZE,
331 p % PAGE_SIZE == 0,
332 0 <= k <= i,
333 forall|j: int|
334 #![trigger addrs[j]]
335 k <= j < addrs.len() ==> {
336 let idx = frame_to_index(addrs[j]);
337 &&& regions.contains(idx)
338 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
339 &&& regions.slot_owners[idx].ref_count() > 0
340 &&& regions.slot_owners[idx].ref_count() <= REF_COUNT_MAX
341 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
342 &&& regions.slot_owners[idx].usage is Frame
343 &&& addrs[j] % PAGE_SIZE == 0
344 &&& addrs[j] < MAX_PADDR
345 &&& addrs[j] == range.start + (j as u64) * PAGE_SIZE
346 },
347 decreases segment.range.end - p,
348 {
349 let ghost reclaim_pre = *regions;
350 let ghost idx_k = frame_to_index(p);
351 proof {
352 broadcast use group_page_meta;
353
354 assert(addrs[k] == p);
355 assert(index_to_meta(idx_k) == frame_to_meta(p));
356 assert(regions.contains(idx_k));
357 }
358 proof_decl! {
359 let tracked from_raw_obl: vstd_extra::drop_tracking::DropObligation<int>;
360 }
361 let frame = unsafe {
362 #[verus_spec(with Tracked(regions) => Tracked(from_raw_obl))]
363 Frame::<M>::from_raw(p)
364 };
365 frame.drop(Tracked(regions), Tracked(from_raw_obl));
366 proof {
367 assert forall|j: int|
368 #![trigger addrs[j]]
369 (k + 1) <= j < addrs.len() implies ({
370 let idx = frame_to_index(addrs[j]);
371 &&& regions.contains(idx)
372 &&& regions.slot_owners[idx] == reclaim_pre.slot_owners[idx]
373 }) by {
374 assert(addrs[j] != p);
375 crate::specs::mm::frame::mapping::lemma_frame_to_index_injective(
376 addrs[j],
377 p,
378 );
379 };
380 }
381 p = p + PAGE_SIZE;
382 proof {
383 k = k + 1;
384 }
385 }
386 return Err(e);
387 },
388 };
389
390 proof_decl! {
391 let tracked redeem_obl = DropObligation::tracked_mint(frame.index());
392 regions.tracked_redeem_frame_obligation(redeem_obl);
393 let tracked md_obl = DropObligation::tracked_mint(frame.index());
394 }
395 proof_with!(Tracked(md_obl));
396 let _ = ManuallyDrop::new(frame);
397 segment.range.end = paddr + PAGE_SIZE;
398 proof {
399 broadcast use group_page_meta;
400
401 regions.lemma_contains_valid_frame_paddr(paddr);
402 let idx = frame_to_index(paddr);
403 axiom_mmio_usage_iff_mmio_paddr(regions.slot_owners[idx]);
404 axiom_mmio_usage_iff_mmio_paddr(regions_pre.slot_owners[idx]);
405 assert(regions_pre.slot_owners[idx].paths_in_pt.is_empty());
406 assert(regions.slot_owners[idx].paths_in_pt
407 == regions_pre.slot_owners[idx].paths_in_pt);
408 assert(regions.slot_owners[idx].usage is Frame);
409 assert(regions.frame_obligations == regions_pre.frame_obligations);
410 addrs.tracked_push(paddr);
411 }
412
413 i += 1;
414 }
415
416 proof {
417 assert(regions.frame_obligations == old(regions).frame_obligations);
427 let ghost before_mint = *regions;
428 crate::specs::mm::frame::segment::tracked_mint_seg_obligations(
429 regions,
430 range.start,
431 addr_len as int,
432 );
433 assert(segment.range == range);
434
435 assert forall|addr: usize|
436 #![trigger frame_to_index(addr)]
437 range.start <= addr < range.end && addr % PAGE_SIZE == 0 implies {
438 regions.contains(frame_to_index(addr))
439 } by {
440 let j = (addr - range.start) / PAGE_SIZE as int;
441 assert(addrs[j as int] == addr);
442 }
443 assert forall|i: int|
444 #![trigger frame_to_index((segment.range.start + i * PAGE_SIZE) as usize)]
445 0 <= i < crate::specs::mm::frame::segment::seg_nframes(segment.range) implies {
446 let idx = frame_to_index((segment.range.start + i * PAGE_SIZE) as usize);
447 &&& regions.frame_obligations.count(idx) >= 1
448 &&& regions.contains(idx)
449 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
450 &&& regions.slot_owners[idx].ref_count() > 0
451 &&& regions.slot_owners[idx].ref_count() <= REF_COUNT_MAX
452 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
453 &&& regions.slot_owners[idx].usage is Frame
454 } by {
455 assert(addrs[i] == segment.range.start + i * PAGE_SIZE);
456 assert(regions.slot_owners == before_mint.slot_owners);
457 assert(regions.slots == before_mint.slots);
458 }
459 assert forall|i: int, j: int|
460 #![trigger frame_to_index((segment.range.start + i * PAGE_SIZE) as usize),
461 frame_to_index((segment.range.start + j * PAGE_SIZE) as usize)]
462 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
463 segment.range,
464 ) implies frame_to_index((segment.range.start + i * PAGE_SIZE) as usize)
465 != frame_to_index((segment.range.start + j * PAGE_SIZE) as usize) by {
466 let p1 = (segment.range.start + i * PAGE_SIZE) as usize;
467 let p2 = (segment.range.start + j * PAGE_SIZE) as usize;
468 assert(p1 != p2);
469 crate::specs::mm::frame::mapping::lemma_frame_to_index_injective(p1, p2);
470 }
471 }
472
473 Ok(segment)
474 }
475
476 #[verus_spec(r =>
495 with
496 Tracked(regions): Tracked<&mut MetaRegionOwners>,
497 requires
498 (Segment {
499 range,
500 _marker: core::marker::PhantomData::<M>,
501 }).invariants(*old(regions)),
502 ensures
503 r.range() == range,
504 r.invariants(*final(regions)),
505 final(regions).inv(),
506 *final(regions) == *old(regions),
507 )]
508 pub(crate) unsafe fn from_raw(range: Range<Paddr>) -> Self {
509 Self { range, _marker: core::marker::PhantomData }
510 }
511}
512
513#[verus_verify]
514impl<M: AnyFrameMeta + ?Sized> Segment<M> {
515 #[verus_verify(dual_spec)]
517 #[verus_spec(
518 returns
519 self.start_paddr(),
520 )]
521 pub fn start_paddr(&self) -> Paddr {
522 self.range.start
523 }
524
525 #[verus_verify(dual_spec)]
527 #[verus_spec(
528 returns
529 self.end_paddr(),
530 )]
531 pub fn end_paddr(&self) -> Paddr {
532 self.range.end
533 }
534
535 #[verus_verify(dual_spec)]
537 #[verus_spec(r =>
538 requires
539 self.inv(),
540 ensures
541 r == self.end_paddr() - self.start_paddr(),
542 returns
543 self.size()
544 )]
545 pub fn size(&self) -> usize {
546 self.range.end - self.range.start
547 }
548
549 pub open spec fn range(&self) -> Range<Paddr> {
550 self.start_paddr()..self.end_paddr()
551 }
552}
553
554#[verus_verify]
555impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Segment<M> {
556 #[verus_spec(r =>
571 with
572 Tracked(regions): Tracked<&mut MetaRegionOwners>,
573 requires
574 self.invariants(*old(regions)),
575 offset % PAGE_SIZE != 0 ==> may_panic(),
576 !(0 < offset && offset < self.size()) ==> may_panic(),
577 ensures
578 final(regions).slots == old(regions).slots,
579 final(regions).slot_owners == old(regions).slot_owners,
580 final(regions).frame_obligations == old(regions).frame_obligations,
581 (r.0, r.1) == self.split_spec(offset),
582 r.0.invariants(*final(regions)),
583 r.1.invariants(*final(regions)),
584 )]
585 #[verifier::spinoff_prover]
586 pub fn split(self, offset: usize) -> (Self, Self) {
587 assert!(offset % PAGE_SIZE == 0);
588 assert!(0 < offset && offset < self.size());
589
590 let ghost old_regions = *regions;
591
592 proof_decl! {
593 let tracked md_obl = DropObligation::tracked_mint(self.range);
594 }
595 proof_with!(Tracked(md_obl));
596 let old = ManuallyDrop::new(self);
597 let at = old.range.start + offset;
598
599 let ghost old_start = old@.start_paddr();
600 let ghost old_end = old@.end_paddr();
601
602 let ghost seg1 = Segment { range: old_start..at, _marker: core::marker::PhantomData::<M> };
603 let ghost seg2 = Segment { range: at..old_end, _marker: core::marker::PhantomData::<M> };
604 proof {
605 assert forall|i: int|
606 #![trigger frame_to_index((seg1.range.start + i * PAGE_SIZE) as usize)]
607 0 <= i < crate::specs::mm::frame::segment::seg_nframes(seg1.range) implies {
608 let idx = frame_to_index((seg1.range.start + i * PAGE_SIZE) as usize);
609 &&& regions.frame_obligations.count(idx) >= 1
610 &&& regions.contains(idx)
611 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
612 &&& regions.slot_owners[idx].ref_count() > 0
613 &&& regions.slot_owners[idx].ref_count() <= REF_COUNT_MAX
614 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
615 &&& regions.slot_owners[idx].usage is Frame
616 } by {
617 old@.relate_regions_at(old_regions, i);
618 }
619 assert forall|i: int|
620 #![trigger frame_to_index((seg2.range.start + i * PAGE_SIZE) as usize)]
621 0 <= i < crate::specs::mm::frame::segment::seg_nframes(seg2.range) implies {
622 let idx = frame_to_index((seg2.range.start + i * PAGE_SIZE) as usize);
623 &&& regions.frame_obligations.count(idx) >= 1
624 &&& regions.contains(idx)
625 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
626 &&& regions.slot_owners[idx].ref_count() > 0
627 &&& regions.slot_owners[idx].ref_count() <= REF_COUNT_MAX
628 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
629 &&& regions.slot_owners[idx].usage is Frame
630 } by {
631 old@.relate_regions_at(old_regions, i + (offset / PAGE_SIZE) as int);
632 }
633
634 assert forall|i: int, j: int|
635 #![trigger frame_to_index((seg1.range.start + i * PAGE_SIZE) as usize),
636 frame_to_index((seg1.range.start + j * PAGE_SIZE) as usize)]
637 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
638 seg1.range,
639 ) implies frame_to_index((seg1.range.start + i * PAGE_SIZE) as usize)
640 != frame_to_index((seg1.range.start + j * PAGE_SIZE) as usize) by {
641 old@.relate_regions_distinct(old_regions, i, j);
642 }
643 assert forall|i: int, j: int|
644 #![trigger frame_to_index((seg2.range.start + i * PAGE_SIZE) as usize),
645 frame_to_index((seg2.range.start + j * PAGE_SIZE) as usize)]
646 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
647 seg2.range,
648 ) implies frame_to_index((seg2.range.start + i * PAGE_SIZE) as usize)
649 != frame_to_index((seg2.range.start + j * PAGE_SIZE) as usize) by {
650 old@.relate_regions_distinct(
651 old_regions,
652 i + (offset / PAGE_SIZE) as int,
653 j + (offset / PAGE_SIZE),
654 );
655 }
656 }
657 (
658 Self { range: old.range.start..at, _marker: core::marker::PhantomData },
659 Self { range: at..old.range.end, _marker: core::marker::PhantomData },
660 )
661 }
662
663 pub open spec fn page_in_range_saturated(
673 self,
674 range: &Range<usize>,
675 regions: MetaRegionOwners,
676 ) -> bool {
677 exists|j: int|
678 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
679 (range.start as int) / (PAGE_SIZE as int) <= j < (range.end as int) / (PAGE_SIZE as int)
680 && regions.slot_owner((self.start_paddr() + j * PAGE_SIZE) as usize).ref_count()
681 >= REF_COUNT_MAX
682 }
683
684 #[verus_spec(r =>
701 with
702 Tracked(regions): Tracked<&mut MetaRegionOwners>,
703 requires
704 self.invariants(*old(regions)),
705 range.start % PAGE_SIZE != 0 ==> may_panic(),
706 range.end % PAGE_SIZE != 0 ==> may_panic(),
707 range.start > range.end ==> may_panic(),
708 range.end > self.size() ==> may_panic(),
709 self.page_in_range_saturated(range, *old(regions)) ==> may_panic(),
710 ensures
711 range.start % PAGE_SIZE == 0,
712 range.end % PAGE_SIZE == 0,
713 range.start <= range.end,
714 self.range.start + range.end <= self.range.end,
715 !self.page_in_range_saturated(range, *old(regions)),
716 r.inv(),
717 r.start_paddr() == self.start_paddr() + range.start,
718 r.end_paddr() == self.start_paddr() + range.end,
719 r.end_paddr() <= self.end_paddr(),
720 final(regions).inv(),
721 final(regions).slots == old(regions).slots,
722 final(regions).slot_owners.dom() == old(regions).slot_owners.dom(),
723 final(regions).frame_obligations == old(regions).frame_obligations,
724 )]
725 #[verifier::spinoff_prover]
726 #[verifier::loop_isolation(false)]
727 pub fn slice(&self, range: &Range<usize>) -> Self {
728 assert!(range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0);
729 assert!(range.start <= range.end && range.end <= self.size());
730 let start = self.range.start + range.start;
731 let end = self.range.start + range.end;
732
733 let mut paddr = start;
734 let ghost addr_len = (end - start) / PAGE_SIZE as int;
735 let ghost first_perm_idx: int = (range.start / PAGE_SIZE) as int;
736 let ghost last_perm_idx: int = (range.end / PAGE_SIZE) as int;
737 let ghost mut i: int = 0;
738 loop
739 invariant
740 self.page_in_range_saturated(range, *old(regions)) ==> may_panic(),
741 regions.inv(),
742 regions.slots == old(regions).slots,
743 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
744 regions.frame_obligations == old(regions).frame_obligations,
745 paddr == (start + i * PAGE_SIZE) as usize,
746 paddr <= end,
747 0 <= i <= addr_len,
748 paddr < end <==> i < addr_len,
749 first_perm_idx + i <= last_perm_idx,
750 forall|j: int|
751 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
752 first_perm_idx + i <= j < last_perm_idx ==> (*regions).slot_owner(
753 (self.range.start + j * PAGE_SIZE) as usize,
754 ) == old(regions).slot_owner((self.range.start + j * PAGE_SIZE) as usize),
755 forall|j: int|
756 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
757 first_perm_idx <= j < first_perm_idx + i ==> old(regions).slot_owner(
758 (self.range.start + j * PAGE_SIZE) as usize,
759 ).ref_count() < REF_COUNT_MAX,
760 decreases addr_len - i,
761 {
762 if paddr >= end {
763 break;
764 }
765 let ghost perm_idx: int = first_perm_idx + i;
766
767 proof {
768 self.relate_regions_at(*old(regions), perm_idx);
769 }
770
771 unsafe {
772 #[verus_spec(with Tracked(regions))]
773 crate::mm::frame::inc_frame_ref_count(paddr)
774 };
775
776 paddr = paddr + PAGE_SIZE;
777
778 proof {
779 i = i + 1;
780 assert forall|j: int|
781 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
782 first_perm_idx + i <= j < last_perm_idx implies (*regions).slot_owner(
783 (self.range.start + j * PAGE_SIZE) as usize,
784 ) == old(regions).slot_owner((self.range.start + j * PAGE_SIZE) as usize) by {};
785 }
786 }
787
788 Self { range: start..end, _marker: core::marker::PhantomData }
789 }
790
791 #[verus_spec(r =>
804 with
805 Tracked(regions): Tracked<&mut MetaRegionOwners>,
806 requires
807 self.invariants(*old(regions)),
808 ensures
809 r == self.range(),
810 final(regions).inv(),
811 *final(regions) == *old(regions),
812 )]
813 pub(crate) fn into_raw(self) -> Range<Paddr> {
814 let range = self.range.clone();
815 proof_decl! {
816 let tracked md_obl = DropObligation::tracked_mint(self.range);
817 }
818 proof_with!(Tracked(md_obl));
819 let _ = ManuallyDrop::new(self);
820
821 range
822 }
823
824 #[verifier::inline]
826 pub open spec fn nrpage_spec(&self) -> usize {
827 self.size() / PAGE_SIZE
828 }
829
830 pub closed spec fn split_spec(self, offset: usize) -> (Self, Self)
832 recommends
833 offset % PAGE_SIZE == 0,
834 0 < offset < self.size(),
835 {
836 let at = (self.start_paddr() + offset) as usize;
837 let idx = at / PAGE_SIZE;
838 (
839 Self { range: self.start_paddr()..at, _marker: core::marker::PhantomData },
840 Self { range: at..self.end_paddr(), _marker: core::marker::PhantomData },
841 )
842 }
843}
844
845pub type SegmentIteratorItem<M> = (Frame<M>, Tracked<DropObligation<int>>);
847
848#[verifier::reject_recursive_types(T)]
851pub tracked struct SegmentIteratorProphecySeq<T> {
852 tracked var: ProphecyGhost<Seq<T>>,
853 ghost done: bool,
854}
855
856impl<T> SegmentIteratorProphecySeq<T> {
857 #[verifier::prophetic]
858 closed spec fn seq(&self) -> Seq<T> {
859 if self.done {
860 Seq::empty()
861 } else {
862 self.var.value()
863 }
864 }
865
866 proof fn new() -> (tracked res: Self)
867 ensures
868 !res.done,
869 {
870 SegmentIteratorProphecySeq { var: ProphecyGhost::new(), done: false }
871 }
872
873 proof fn resolve_cons(tracked &mut self, value: T)
874 requires
875 !old(self).done,
876 ensures
877 !final(self).done,
878 old(self).seq() == seq![value] + final(self).seq(),
879 {
880 let tracked mut var = ProphecyGhost::new();
881 tracked_swap(&mut var, &mut self.var);
882 var.resolve_dependent(&self.var, |tail| seq![value] + tail);
883 }
884
885 proof fn resolve_nil(tracked &mut self)
886 ensures
887 old(self).seq() == Seq::<T>::empty(),
888 final(self).seq() == Seq::<T>::empty(),
889 final(self).done,
890 {
891 if !self.done {
892 let tracked mut var = ProphecyGhost::new();
893 tracked_swap(&mut var, &mut self.var);
894 var.resolve(seq![]);
895 self.done = true;
896 }
897 }
898}
899
900#[verifier::reject_recursive_types(M)]
905pub struct SegmentIterator<'a, M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> {
906 segment: &'a Segment<M>,
907 range: Range<Paddr>,
908 tracked_regions: Tracked<&'a mut MetaRegionOwners>,
909 tracked_remaining: Tracked<SegmentIteratorProphecySeq<SegmentIteratorItem<M>>>,
910}
911
912#[verus_verify]
913impl<'a, M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> SegmentIterator<'a, M> {
914 pub closed spec fn segment_ref(&self) -> &'a Segment<M> {
915 self.segment
916 }
917
918 pub closed spec fn range_spec(&self) -> Range<Paddr> {
919 self.range
920 }
921
922 pub closed spec fn current_segment(&self) -> Segment<M> {
923 Segment { range: self.range.start..self.range.end, _marker: core::marker::PhantomData::<M> }
924 }
925
926 #[verifier::prophetic]
927 pub closed spec fn remaining_spec(&self) -> Seq<SegmentIteratorItem<M>> {
928 self.tracked_remaining@.seq()
929 }
930
931 #[verifier::type_invariant]
932 pub closed spec fn type_inv(self) -> bool {
933 &&& self.segment.inv()
934 &&& self.segment.range.start <= self.range.start
935 &&& self.range.end == self.segment.range.end
936 &&& self.current_segment().invariants(*self.tracked_regions@)
937 &&& self.range.start < self.range.end ==> !self.tracked_remaining@.done
938 }
939
940 #[verus_spec(res =>
941 with
942 Tracked(regions): Tracked<&'a mut MetaRegionOwners>,
943 requires
944 segment.invariants(*regions),
945 ensures
946 res.segment_ref() == segment,
947 res.range_spec() == segment.range,
948 IteratorSpec::decrease(&res) is Some,
949 )]
950 pub fn new(segment: &'a Segment<M>) -> Self {
951 Self {
952 segment,
953 range: segment.range.start..segment.range.end,
954 tracked_regions: Tracked(regions),
955 tracked_remaining: Tracked(SegmentIteratorProphecySeq::new()),
956 }
957 }
958
959 #[verus_spec(res =>
988 with
989 Tracked(regions_ref): Tracked<&mut &'a mut MetaRegionOwners>,
990 Tracked(remaining): Tracked<&mut SegmentIteratorProphecySeq<SegmentIteratorItem<M>>>,
991 requires
992 segment.inv(),
993 segment.range.start <= old(range).start,
994 old(range).end == segment.range.end,
995 (Segment {
996 range: old(range).start..old(range).end,
997 _marker: core::marker::PhantomData::<M>,
998 }).invariants(**old(regions_ref)),
999 old(range).start < old(range).end ==> !old(remaining).done,
1000 ensures
1001 segment.inv(),
1002 segment.range.start <= final(range).start,
1003 final(range).end == segment.range.end,
1004 (Segment {
1005 range: final(range).start..final(range).end,
1006 _marker: core::marker::PhantomData::<M>,
1007 }).invariants(**final(regions_ref)),
1008 final(range).start < final(range).end ==> !final(remaining).done,
1009 match res {
1010 None => {
1011 &&& final(range).start == old(range).start
1012 &&& final(range).end == old(range).end
1013 &&& old(remaining).seq() == Seq::<SegmentIteratorItem<M>>::empty()
1014 &&& final(remaining).seq() == Seq::<SegmentIteratorItem<M>>::empty()
1015 },
1016 Some(item) => {
1017 &&& final(range).start == old(range).start + PAGE_SIZE
1018 &&& final(range).end == old(range).end
1019 &&& item.0.start_paddr_spec() == old(range).start
1020 &&& old(remaining).seq() == seq![item] + final(remaining).seq()
1021 },
1022 },
1023 no_unwind
1024 )]
1025 fn next_inner(segment: &'a Segment<M>, range: &mut Range<Paddr>) -> (res: Option<
1026 SegmentIteratorItem<M>,
1027 >) {
1028 if range.start < range.end {
1029 let ghost old_remaining = remaining.seq();
1030 let ghost old_range = range.start..range.end;
1031 let ghost old_segment = Segment {
1032 range: old_range.start..old_range.end,
1033 _marker: core::marker::PhantomData::<M>,
1034 };
1035 let ghost old_regions = **regions_ref;
1036 let paddr = range.start;
1037
1038 proof {
1039 old_segment.relate_regions_at(old_regions, 0);
1040 assert(paddr == old_range.start);
1041 }
1042
1043 proof_decl! {
1044 let tracked from_raw_obl: DropObligation<int>;
1045 }
1046 let frame = unsafe {
1047 #[verus_spec(with Tracked(*regions_ref) => Tracked(from_raw_obl))]
1048 Frame::<M>::from_raw(paddr)
1049 };
1050
1051 proof {
1052 let new_range = ((old_range.start + PAGE_SIZE) as usize)..old_range.end;
1053 let ghost new_segment = Segment {
1054 range: new_range.start..new_range.end,
1055 _marker: core::marker::PhantomData::<M>,
1056 };
1057 let tracked redeem_tok = DropObligation::tracked_mint(frame.index());
1058 (*regions_ref).tracked_redeem_frame_obligation(redeem_tok);
1059 assert((**regions_ref).frame_obligations == old_regions.frame_obligations);
1060
1061 assert forall|i: int|
1062 #![trigger frame_to_index((new_segment.range.start + i * PAGE_SIZE) as usize)]
1063 0 <= i < crate::specs::mm::frame::segment::seg_nframes(
1064 new_segment.range,
1065 ) implies {
1066 let idx = frame_to_index((new_segment.range.start + i * PAGE_SIZE) as usize);
1067 &&& (**regions_ref).frame_obligations.count(idx) >= 1
1068 &&& (**regions_ref).contains(idx)
1069 &&& (**regions_ref).slot_owners[idx].slot_vaddr == index_to_meta(idx)
1070 &&& 0 < (**regions_ref).slot_owners[idx].ref_count() <= REF_COUNT_MAX
1071 &&& (**regions_ref).slot_owners[idx].paths_in_pt.is_empty()
1072 &&& (**regions_ref).slot_owners[idx].usage is Frame
1073 } by {
1074 old_segment.relate_regions_at(old_regions, i + 1);
1075 old_segment.relate_regions_distinct(old_regions, 0, i + 1);
1076 }
1077 assert forall|i: int, j: int|
1078 #![trigger frame_to_index((new_segment.range.start + i * PAGE_SIZE) as usize),
1079 frame_to_index((new_segment.range.start + j * PAGE_SIZE) as usize)]
1080 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
1081 new_segment.range,
1082 ) implies frame_to_index((new_segment.range.start + i * PAGE_SIZE) as usize)
1083 != frame_to_index((new_segment.range.start + j * PAGE_SIZE) as usize) by {
1084 old_segment.relate_regions_distinct(old_regions, i + 1, j + 1);
1085 }
1086 broadcast use group_page_meta;
1087
1088 assert((**regions_ref).slots[frame.index()].pptr() == frame.ptr);
1089 assert(frame.wf_with_region(**regions_ref));
1090 }
1091
1092 range.start = range.start + PAGE_SIZE;
1093 let item = (frame, Tracked(from_raw_obl));
1094 proof {
1095 remaining.resolve_cons(item);
1096 broadcast use vstd::seq::group_seq_lemmas;
1097
1098 assert(remaining.seq() == old_remaining.drop_first());
1099 assert(item == old_remaining[0]);
1100 }
1101 Some(item)
1102 } else {
1103 let ghost old_remaining = remaining.seq();
1104 proof {
1105 remaining.resolve_nil();
1106 assert(remaining.seq() == old_remaining);
1107 }
1108 None
1109 }
1110 }
1111}
1112
1113impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> IteratorSpecImpl for SegmentIterator<
1114 '_,
1115 M,
1116> {
1117 open spec fn obeys_prophetic_iter_laws(&self) -> bool {
1118 true
1119 }
1120
1121 #[verifier::prophetic]
1122 closed spec fn remaining(&self) -> Seq<Self::Item> {
1123 self.remaining_spec()
1124 }
1125
1126 #[verifier::prophetic]
1127 closed spec fn will_return_none(&self) -> bool {
1128 true
1129 }
1130
1131 closed spec fn decrease(&self) -> Option<nat> {
1132 Some((self.range.end - self.range.start) as nat)
1133 }
1134
1135 open spec fn peek(&self, index: int) -> Option<Self::Item> {
1136 None
1137 }
1138}
1139
1140impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Iterator for SegmentIterator<'_, M> {
1141 type Item = SegmentIteratorItem<M>;
1142
1143 fn next(&mut self) -> Option<Self::Item> {
1145 proof {
1146 use_type_invariant(&*self);
1147 }
1148
1149 #[verus_spec(with
1150 Tracked(self.tracked_regions.borrow_mut()),
1151 Tracked(self.tracked_remaining.borrow_mut()),
1152 )]
1153 SegmentIterator::next_inner(self.segment, &mut self.range)
1154 }
1155}
1156
1157#[verus_verify]
1158impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> From<Frame<M>> for Segment<M> {
1159 #[verifier::external_body]
1168 fn from(frame: Frame<M>) -> Self {
1169 let pa = frame.start_paddr();
1170 let _ = core::mem::ManuallyDrop::new(frame);
1171 Self { range: pa..(pa + PAGE_SIZE), _marker: core::marker::PhantomData }
1172 }
1173}
1174
1175impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Iterator for Segment<M> {
1176 type Item = Frame<M>;
1177
1178 #[verifier::external_body]
1185 fn next(&mut self) -> Option<Self::Item> {
1186 if self.range.start < self.range.end {
1187 let frame = unsafe { Frame::<M>::from_raw(self.range.start) };
1190 self.range.start = self.range.start + PAGE_SIZE;
1191 Some(frame)
1192 } else {
1193 None
1194 }
1195 }
1196}
1197
1198impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Segment<M> {
1199 #[verus_spec(
1208 with Tracked(regions): Tracked<&mut MetaRegionOwners>
1209 requires
1210 self.invariants(*old(regions)),
1211 forall|i: int|
1212 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1213 0 <= i < crate::specs::mm::frame::segment::seg_nframes(self.range) ==> {
1214 let idx = frame_to_index((self.range.start + i * PAGE_SIZE) as usize);
1215 old(regions).slot_owners[idx].ref_count() == 1 ==> {
1216 &&& old(regions).slot_owners[idx].storage_perm().is_init()
1217 &&& old(regions).slot_owners[idx].in_list_perm.value() == 0
1218 }
1219 },
1220 ensures
1221 final(regions).inv(),
1222 )]
1223 pub fn drop(self) {
1224 let ghost n = crate::specs::mm::frame::segment::seg_nframes(self.range);
1225 let mut paddr = self.range.start;
1226
1227 let ghost mut k: int = 0;
1228
1229 assert forall|i: int| #![trigger frame_idx_at(self.range.start, i)] 0 <= i < n implies {
1230 let idx = frame_idx_at(self.range.start, i);
1231 old(regions).slot_owners[idx].ref_count() == 1 ==> {
1232 &&& old(regions).slot_owners[idx].storage_perm().is_init()
1233 &&& old(regions).slot_owners[idx].in_list_perm.value() == 0
1234 }
1235 } by {};
1236
1237 proof {
1238 assert forall|i: int|
1239 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1240 0 <= i < n implies old(regions).frame_obligations.count(
1241 frame_to_index((self.range.start + i * PAGE_SIZE) as usize),
1242 ) >= 1 by {
1243 self.relate_regions_at(*old(regions), i);
1244 };
1245 assert forall|i: int, j: int|
1246 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize),
1247 frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1248 0 <= i < j < n implies frame_to_index((self.range.start + i * PAGE_SIZE) as usize)
1249 != frame_to_index((self.range.start + j * PAGE_SIZE) as usize) by {
1250 self.relate_regions_distinct(*old(regions), i, j);
1251 };
1252 crate::specs::mm::frame::segment::tracked_redeem_seg_obligations(
1253 regions,
1254 self.range.start,
1255 n,
1256 );
1257 }
1258
1259 loop
1260 invariant
1261 regions.inv(),
1262 self.inv(),
1263 self.range.start <= paddr <= self.range.end,
1264 paddr == (self.range.start + k * PAGE_SIZE) as usize,
1265 paddr % PAGE_SIZE == 0,
1266 paddr <= MAX_PADDR,
1267 0 <= k <= n,
1268 n == (self.range.end - self.range.start) / PAGE_SIZE as int,
1269 paddr < self.range.end <==> k < n,
1270 forall|j: int|
1271 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1272 k <= j < n ==> {
1273 let idx = frame_to_index((self.range.start + j * PAGE_SIZE) as usize);
1274 &&& regions.contains(idx)
1275 &&& regions.slot_owners[idx] == old(regions).slot_owners[idx]
1276 },
1277 forall|j: int|
1278 #![trigger frame_idx_at(self.range.start, j)]
1279 k <= j < n ==> regions.contains(frame_idx_at(self.range.start, j))
1280 && regions.slot_owners[frame_idx_at(self.range.start, j)] == old(
1281 regions,
1282 ).slot_owners[frame_idx_at(self.range.start, j)],
1283 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
1284 self.invariants(*old(regions)),
1285 forall|i: int|
1286 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1287 0 <= i < n ==> {
1288 let idx = frame_to_index((self.range.start + i * PAGE_SIZE) as usize);
1289 old(regions).slot_owners[idx].ref_count() == 1 ==> {
1290 &&& old(regions).slot_owners[idx].storage_perm().is_init()
1291 &&& old(regions).slot_owners[idx].in_list_perm.value() == 0
1292 }
1293 },
1294 decreases n - k,
1295 {
1296 if paddr >= self.range.end {
1297 break;
1298 }
1299 proof {
1300 self.relate_regions_at(*old(regions), k);
1301 }
1302
1303 proof_decl! {
1304 let tracked from_raw_obl: vstd_extra::drop_tracking::DropObligation<int>;
1305 }
1306
1307 let frame = unsafe {
1313 #[verus_spec(with Tracked(regions) => Tracked(from_raw_obl))]
1314 Frame::<M>::from_raw(paddr)
1315 };
1316
1317 frame.drop(Tracked(regions), Tracked(from_raw_obl));
1318
1319 proof {
1320 assert forall|j: int|
1321 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1322 (k + 1) <= j < n implies {
1323 let idx = frame_to_index((self.range.start + j * PAGE_SIZE) as usize);
1324 &&& regions.contains(idx)
1325 &&& regions.slot_owners[idx] == old(regions).slot_owners[idx]
1326 } by {
1327 self.relate_regions_distinct(*old(regions), k, j);
1328 };
1329 }
1330
1331 paddr = paddr + PAGE_SIZE;
1332
1333 proof {
1334 k = k + 1;
1335 }
1336 }
1337 }
1338}
1339
1340impl<M: AnyFrameMeta + ?Sized> Inv for Segment<M> {
1447 open spec fn inv(self) -> bool {
1452 &&& self.start_paddr() % PAGE_SIZE == 0
1453 &&& self.end_paddr() % PAGE_SIZE == 0
1454 &&& self.start_paddr() <= self.end_paddr() <= MAX_PADDR
1455 }
1456}
1457
1458}