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