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.slots.contains_key(idx)
107 &&& valid_frame_paddr(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 &&& valid_frame_paddr(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 =>
209 with
210 Tracked(regions): Tracked<&mut MetaRegionOwners>,
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 &&& seg.invariants(*final(regions))
232 &&& crate::specs::mm::frame::segment::seg_obligations_minted(
233 *old(regions),
234 *final(regions),
235 range.start,
236 crate::specs::mm::frame::segment::seg_nframes(range),
237 )
238 &&& forall|paddr: Paddr|
239 #![trigger frame_to_index(paddr)]
240 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
241 ==> final(regions).slots.contains_key(frame_to_index(paddr))
242 &&& range.start < range.end <= MAX_PADDR
243 },
244 )]
245 pub fn from_unused(range: Range<Paddr>, metadata_fn: impl Fn(Paddr) -> (Paddr, M)) -> (res:
246 Result<Self, GetFrameError>) {
247 proof_decl! {
248 let tracked mut addrs = Seq::<usize>::tracked_empty();
249 }
250
251 if range.start % PAGE_SIZE != 0 || range.end % PAGE_SIZE != 0 {
252 return Err(GetFrameError::NotAligned);
253 }
254 if range.end > MAX_PADDR {
255 return Err(GetFrameError::OutOfBound);
256 }
257 assert!(range.start < range.end);
258
259 let mut segment = Self {
260 range: range.start..range.start,
261 _marker: core::marker::PhantomData,
262 };
263
264 let mut i = 0;
265 let addr_len = (range.end - range.start) / PAGE_SIZE;
266
267 while i < addr_len
268 invariant
269 i <= addr_len,
270 i == addrs.len(),
271 range.start % PAGE_SIZE == 0,
272 range.end % PAGE_SIZE == 0,
273 range.end <= MAX_PADDR,
274 range.start <= range.start + i * PAGE_SIZE <= range.end,
275 range.end == range.start + addr_len * PAGE_SIZE,
276 addr_len == (range.end - range.start) / PAGE_SIZE as int,
277 i <= addr_len,
278 forall|paddr_in: Paddr|
279 (range.start + i * PAGE_SIZE <= paddr_in < range.end && paddr_in % PAGE_SIZE
280 == 0) ==> {
281 &&& metadata_fn.requires((paddr_in,))
282 },
283 forall|paddr_in: Paddr, paddr_out: Paddr, m: M|
284 range.start + i * PAGE_SIZE <= paddr_in < range.end && paddr_in % PAGE_SIZE == 0
285 && metadata_fn.ensures((paddr_in,), (paddr_out, m)) ==> paddr_in
286 == paddr_out,
287 forall|j: int|
288 #![trigger addrs[j]]
289 0 <= j < addrs.len() ==> {
290 let idx = frame_to_index(addrs[j]);
291 &&& regions.slots.contains_key(idx)
292 &&& regions.slot_owners.contains_key(idx)
293 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
294 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
295 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
296 <= crate::mm::frame::meta::REF_COUNT_MAX
297 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
298 &&& regions.slot_owners[idx].usage is Frame
299 &&& addrs[j] % PAGE_SIZE == 0
300 &&& addrs[j] < MAX_PADDR
301 &&& addrs[j] == range.start + (j as u64) * PAGE_SIZE
302 },
303 regions.inv(),
304 regions.frame_obligations == old(regions).frame_obligations,
305 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
306 segment.range.start == range.start,
307 segment.range.end == range.start + i * PAGE_SIZE,
308 ensures
309 i == addr_len,
310 decreases addr_len - i,
311 {
312 let paddr_in = range.start + i * PAGE_SIZE;
313 let (paddr, meta) = metadata_fn(paddr_in);
314
315 let ghost regions_pre = *regions;
316 let res = #[verus_spec(with Tracked(regions))]
317 Frame::<M>::from_unused(paddr, meta);
318 let frame = match res {
319 Ok(f) => f,
320 Err(e) => {
321 let mut p = range.start;
322 let ghost mut k: int = 0;
323 while p < segment.range.end
324 invariant
325 regions.inv(),
326 regions.frame_obligations == old(regions).frame_obligations,
327 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
328 range.start % PAGE_SIZE == 0,
329 i == addrs.len(),
330 segment.range.end == range.start + i * PAGE_SIZE,
331 segment.range.end <= MAX_PADDR,
332 range.start <= p <= segment.range.end,
333 p == range.start + k * PAGE_SIZE,
334 p % PAGE_SIZE == 0,
335 0 <= k <= i,
336 forall|j: int|
337 #![trigger addrs[j]]
338 k <= j < addrs.len() ==> {
339 let idx = frame_to_index(addrs[j]);
340 &&& regions.slots.contains_key(idx)
341 &&& regions.slot_owners.contains_key(idx)
342 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
343 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
344 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
345 <= crate::mm::frame::meta::REF_COUNT_MAX
346 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
347 &&& regions.slot_owners[idx].usage is Frame
348 &&& addrs[j] % PAGE_SIZE == 0
349 &&& addrs[j] < MAX_PADDR
350 &&& addrs[j] == range.start + (j as u64) * PAGE_SIZE
351 },
352 decreases segment.range.end - p,
353 {
354 let ghost reclaim_pre = *regions;
355 let ghost idx_k = frame_to_index(p);
356 proof {
357 broadcast use group_page_meta;
358
359 assert(addrs[k] == p);
360 assert(index_to_meta(idx_k) == frame_to_meta(p));
361 assert(regions.slots.contains_key(idx_k));
362 }
363 proof_decl! {
364 let tracked from_raw_obl: vstd_extra::drop_tracking::DropObligation<int>;
365 }
366 let frame = unsafe {
367 #[verus_spec(with Tracked(regions) => Tracked(from_raw_obl))]
368 Frame::<M>::from_raw(p)
369 };
370 frame.drop(Tracked(regions), Tracked(from_raw_obl));
371 proof {
372 assert forall|j: int|
373 #![trigger addrs[j]]
374 (k + 1) <= j < addrs.len() implies ({
375 let idx = frame_to_index(addrs[j]);
376 &&& regions.slots.contains_key(idx)
377 &&& regions.slot_owners.contains_key(idx)
378 &&& regions.slot_owners[idx] == reclaim_pre.slot_owners[idx]
379 }) by {
380 assert(addrs[j] != p);
381 crate::specs::mm::frame::mapping::lemma_frame_to_index_injective(
382 addrs[j],
383 p,
384 );
385 };
386 }
387 p = p + PAGE_SIZE;
388 proof {
389 k = k + 1;
390 }
391 }
392 return Err(e);
393 },
394 };
395
396 proof_decl! {
397 let tracked redeem_obl = DropObligation::tracked_mint(frame.index());
398 regions.tracked_redeem_frame_obligation(redeem_obl);
399 let tracked md_obl = DropObligation::tracked_mint(frame.index());
400 }
401 proof_with!(Tracked(md_obl));
402 let _ = ManuallyDrop::new(frame);
403 segment.range.end = paddr + PAGE_SIZE;
404 proof {
405 broadcast use group_page_meta;
406
407 regions.inv_implies_correct_addr(paddr);
408 let idx = frame_to_index(paddr);
409 axiom_mmio_usage_iff_mmio_paddr(regions.slot_owners[idx]);
410 axiom_mmio_usage_iff_mmio_paddr(regions_pre.slot_owners[idx]);
411 assert(regions_pre.slot_owners[idx].paths_in_pt.is_empty());
412 assert(regions.slot_owners[idx].paths_in_pt
413 == regions_pre.slot_owners[idx].paths_in_pt);
414 assert(regions.slot_owners[idx].usage is Frame);
415 assert(regions.frame_obligations == regions_pre.frame_obligations);
416 addrs.tracked_push(paddr);
417 }
418
419 i += 1;
420 }
421
422 proof {
423 assert(regions.frame_obligations == old(regions).frame_obligations);
433 let ghost before_mint = *regions;
434 crate::specs::mm::frame::segment::tracked_mint_seg_obligations(
435 regions,
436 range.start,
437 addr_len as int,
438 );
439 assert(segment.range == range);
440
441 assert forall|addr: usize|
442 #![trigger frame_to_index(addr)]
443 range.start <= addr < range.end && addr % PAGE_SIZE == 0 implies {
444 regions.slots.contains_key(frame_to_index(addr))
445 } by {
446 let j = (addr - range.start) / PAGE_SIZE as int;
447 assert(addrs[j as int] == addr);
448 }
449 assert forall|i: int|
450 #![trigger frame_to_index((segment.range.start + i * PAGE_SIZE) as usize)]
451 0 <= i < crate::specs::mm::frame::segment::seg_nframes(segment.range) implies {
452 let idx = frame_to_index((segment.range.start + i * PAGE_SIZE) as usize);
453 &&& regions.frame_obligations.count(idx) >= 1
454 &&& regions.slot_owners.contains_key(idx)
455 &&& regions.slots.contains_key(idx)
456 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
457 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
458 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
459 <= crate::mm::frame::meta::REF_COUNT_MAX
460 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
461 &&& regions.slot_owners[idx].usage is Frame
462 } by {
463 assert(addrs[i] == segment.range.start + i * PAGE_SIZE);
464 assert(regions.slot_owners == before_mint.slot_owners);
465 assert(regions.slots == before_mint.slots);
466 }
467 assert forall|i: int, j: int|
468 #![trigger frame_to_index((segment.range.start + i * PAGE_SIZE) as usize),
469 frame_to_index((segment.range.start + j * PAGE_SIZE) as usize)]
470 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
471 segment.range,
472 ) implies frame_to_index((segment.range.start + i * PAGE_SIZE) as usize)
473 != frame_to_index((segment.range.start + j * PAGE_SIZE) as usize) by {
474 let p1 = (segment.range.start + i * PAGE_SIZE) as usize;
475 let p2 = (segment.range.start + j * PAGE_SIZE) as usize;
476 assert(p1 != p2);
477 crate::specs::mm::frame::mapping::lemma_frame_to_index_injective(p1, p2);
478 }
479 }
480
481 Ok(segment)
482 }
483
484 #[verus_spec(r =>
503 with
504 Tracked(regions): Tracked<&mut MetaRegionOwners>,
505 requires
506 (Segment {
507 range,
508 _marker: core::marker::PhantomData::<M>,
509 }).invariants(*old(regions)),
510 ensures
511 r.range() == range,
512 r.invariants(*final(regions)),
513 final(regions).inv(),
514 *final(regions) == *old(regions),
515 )]
516 pub(crate) unsafe fn from_raw(range: Range<Paddr>) -> Self {
517 Self { range, _marker: core::marker::PhantomData }
518 }
519}
520
521#[verus_verify]
522impl<M: AnyFrameMeta + ?Sized> Segment<M> {
523 #[verus_verify(dual_spec)]
525 #[verus_spec(
526 returns
527 self.start_paddr(),
528 )]
529 pub fn start_paddr(&self) -> Paddr {
530 self.range.start
531 }
532
533 #[verus_verify(dual_spec)]
535 #[verus_spec(
536 returns
537 self.end_paddr(),
538 )]
539 pub fn end_paddr(&self) -> Paddr {
540 self.range.end
541 }
542
543 #[verus_verify(dual_spec)]
545 #[verus_spec(r =>
546 requires
547 self.inv(),
548 ensures
549 r == self.end_paddr() - self.start_paddr(),
550 returns
551 self.size()
552 )]
553 pub fn size(&self) -> usize {
554 self.range.end - self.range.start
555 }
556
557 pub open spec fn range(&self) -> Range<Paddr> {
558 self.start_paddr()..self.end_paddr()
559 }
560}
561
562#[verus_verify]
563impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Segment<M> {
564 #[verus_spec(r =>
579 with
580 Tracked(regions): Tracked<&mut MetaRegionOwners>,
581 requires
582 self.invariants(*old(regions)),
583 offset % PAGE_SIZE != 0 ==> may_panic(),
584 !(0 < offset && offset < self.size()) ==> may_panic(),
585 ensures
586 final(regions).slots == old(regions).slots,
587 final(regions).slot_owners == old(regions).slot_owners,
588 final(regions).frame_obligations == old(regions).frame_obligations,
589 (r.0, r.1) == self.split_spec(offset),
590 r.0.invariants(*final(regions)),
591 r.1.invariants(*final(regions)),
592 )]
593 #[verifier::spinoff_prover]
594 pub fn split(self, offset: usize) -> (Self, Self) {
595 assert!(offset % PAGE_SIZE == 0);
596 assert!(0 < offset && offset < self.size());
597
598 let ghost old_regions = *regions;
599
600 proof_decl! {
601 let tracked md_obl = DropObligation::tracked_mint(self.range);
602 }
603 proof_with!(Tracked(md_obl));
604 let old = ManuallyDrop::new(self);
605 let at = old.range.start + offset;
606
607 let ghost old_start = old@.start_paddr();
608 let ghost old_end = old@.end_paddr();
609
610 let ghost seg1 = Segment { range: old_start..at, _marker: core::marker::PhantomData::<M> };
611 let ghost seg2 = Segment { range: at..old_end, _marker: core::marker::PhantomData::<M> };
612 proof {
613 assert forall|i: int|
614 #![trigger frame_to_index((seg1.range.start + i * PAGE_SIZE) as usize)]
615 0 <= i < crate::specs::mm::frame::segment::seg_nframes(seg1.range) implies {
616 let idx = frame_to_index((seg1.range.start + i * PAGE_SIZE) as usize);
617 &&& regions.frame_obligations.count(idx) >= 1
618 &&& regions.slot_owners.contains_key(idx)
619 &&& regions.slots.contains_key(idx)
620 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
621 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
622 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
623 <= crate::mm::frame::meta::REF_COUNT_MAX
624 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
625 &&& regions.slot_owners[idx].usage is Frame
626 } by {
627 old@.relate_regions_at(old_regions, i);
628 }
629 assert forall|i: int|
630 #![trigger frame_to_index((seg2.range.start + i * PAGE_SIZE) as usize)]
631 0 <= i < crate::specs::mm::frame::segment::seg_nframes(seg2.range) implies {
632 let idx = frame_to_index((seg2.range.start + i * PAGE_SIZE) as usize);
633 &&& regions.frame_obligations.count(idx) >= 1
634 &&& regions.slot_owners.contains_key(idx)
635 &&& regions.slots.contains_key(idx)
636 &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
637 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
638 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
639 <= crate::mm::frame::meta::REF_COUNT_MAX
640 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
641 &&& regions.slot_owners[idx].usage is Frame
642 } by {
643 old@.relate_regions_at(old_regions, i + (offset / PAGE_SIZE) as int);
644 }
645
646 assert forall|i: int, j: int|
647 #![trigger frame_to_index((seg1.range.start + i * PAGE_SIZE) as usize),
648 frame_to_index((seg1.range.start + j * PAGE_SIZE) as usize)]
649 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
650 seg1.range,
651 ) implies frame_to_index((seg1.range.start + i * PAGE_SIZE) as usize)
652 != frame_to_index((seg1.range.start + j * PAGE_SIZE) as usize) by {
653 old@.relate_regions_distinct(old_regions, i, j);
654 }
655 assert forall|i: int, j: int|
656 #![trigger frame_to_index((seg2.range.start + i * PAGE_SIZE) as usize),
657 frame_to_index((seg2.range.start + j * PAGE_SIZE) as usize)]
658 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
659 seg2.range,
660 ) implies frame_to_index((seg2.range.start + i * PAGE_SIZE) as usize)
661 != frame_to_index((seg2.range.start + j * PAGE_SIZE) as usize) by {
662 old@.relate_regions_distinct(
663 old_regions,
664 i + (offset / PAGE_SIZE) as int,
665 j + (offset / PAGE_SIZE),
666 );
667 }
668 }
669 (
670 Self { range: old.range.start..at, _marker: core::marker::PhantomData },
671 Self { range: at..old.range.end, _marker: core::marker::PhantomData },
672 )
673 }
674
675 pub open spec fn page_in_range_saturated(
685 self,
686 range: &Range<usize>,
687 regions: MetaRegionOwners,
688 ) -> bool {
689 exists|j: int|
690 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
691 (range.start as int) / (PAGE_SIZE as int) <= j < (range.end as int) / (PAGE_SIZE as int)
692 && regions.slot_owners[frame_to_index(
693 (self.start_paddr() + j * PAGE_SIZE) as usize,
694 )].inner_perms.ref_count.value() >= REF_COUNT_MAX
695 }
696
697 #[verus_spec(r =>
714 with
715 Tracked(regions): Tracked<&mut MetaRegionOwners>,
716 requires
717 self.invariants(*old(regions)),
718 range.start % PAGE_SIZE != 0 ==> may_panic(),
719 range.end % PAGE_SIZE != 0 ==> may_panic(),
720 range.start > range.end ==> may_panic(),
721 range.end > self.size() ==> may_panic(),
722 self.page_in_range_saturated(range, *old(regions)) ==> may_panic(),
723 ensures
724 range.start % PAGE_SIZE == 0,
725 range.end % PAGE_SIZE == 0,
726 range.start <= range.end,
727 self.range.start + range.end <= self.range.end,
728 !self.page_in_range_saturated(range, *old(regions)),
729 r.inv(),
730 r.start_paddr() == self.start_paddr() + range.start,
731 r.end_paddr() == self.start_paddr() + range.end,
732 r.end_paddr() <= self.end_paddr(),
733 final(regions).inv(),
734 final(regions).slots == old(regions).slots,
735 final(regions).slot_owners.dom() == old(regions).slot_owners.dom(),
736 final(regions).frame_obligations == old(regions).frame_obligations,
737 )]
738 #[verifier::spinoff_prover]
739 #[verifier::loop_isolation(false)]
740 pub fn slice(&self, range: &Range<usize>) -> Self {
741 assert!(range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0);
742 assert!(range.start <= range.end && range.end <= self.size());
743 let start = self.range.start + range.start;
744 let end = self.range.start + range.end;
745
746 let mut paddr = start;
747 let ghost addr_len = (end - start) / PAGE_SIZE as int;
748 let ghost first_perm_idx: int = (range.start / PAGE_SIZE) as int;
749 let ghost last_perm_idx: int = (range.end / PAGE_SIZE) as int;
750 let ghost mut i: int = 0;
751 loop
752 invariant
753 self.page_in_range_saturated(range, *old(regions)) ==> may_panic(),
754 regions.inv(),
755 regions.slots == old(regions).slots,
756 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
757 regions.frame_obligations == old(regions).frame_obligations,
758 paddr == (start + i * PAGE_SIZE) as usize,
759 paddr <= end,
760 0 <= i <= addr_len,
761 paddr < end <==> i < addr_len,
762 first_perm_idx + i <= last_perm_idx,
763 forall|j: int|
764 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
765 first_perm_idx + i <= j < last_perm_idx ==> (
766 *regions).slot_owners[frame_to_index(
767 (self.range.start + j * PAGE_SIZE) as usize,
768 )] == old(regions).slot_owners[frame_to_index(
769 (self.range.start + j * PAGE_SIZE) as usize,
770 )],
771 forall|j: int|
772 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
773 first_perm_idx <= j < first_perm_idx + i ==> old(
774 regions,
775 ).slot_owners[frame_to_index(
776 (self.range.start + j * PAGE_SIZE) as usize,
777 )].inner_perms.ref_count.value() < REF_COUNT_MAX,
778 decreases addr_len - i,
779 {
780 if paddr >= end {
781 break;
782 }
783 let ghost perm_idx: int = first_perm_idx + i;
784
785 proof {
786 self.relate_regions_at(*old(regions), perm_idx);
787 }
788
789 unsafe {
790 #[verus_spec(with Tracked(regions))]
791 crate::mm::frame::inc_frame_ref_count(paddr)
792 };
793
794 paddr = paddr + PAGE_SIZE;
795
796 proof {
797 i = i + 1;
798 assert forall|j: int|
799 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
800 first_perm_idx + i <= j < last_perm_idx implies (
801 *regions).slot_owners[frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
802 == old(regions).slot_owners[frame_to_index(
803 (self.range.start + j * PAGE_SIZE) as usize,
804 )] by {};
805 }
806 }
807
808 Self { range: start..end, _marker: core::marker::PhantomData }
809 }
810
811 #[verus_spec(r =>
824 with
825 Tracked(regions): Tracked<&mut MetaRegionOwners>,
826 requires
827 self.invariants(*old(regions)),
828 ensures
829 r == self.range(),
830 final(regions).inv(),
831 *final(regions) == *old(regions),
832 )]
833 pub(crate) fn into_raw(self) -> Range<Paddr> {
834 let range = self.range.clone();
835 proof_decl! {
836 let tracked md_obl = DropObligation::tracked_mint(self.range);
837 }
838 proof_with!(Tracked(md_obl));
839 let _ = ManuallyDrop::new(self);
840
841 range
842 }
843
844 #[verifier::inline]
846 pub open spec fn nrpage_spec(&self) -> usize
847 recommends
848 self.inv(),
849 {
850 self.size() / PAGE_SIZE
851 }
852
853 pub closed spec fn split_spec(self, offset: usize) -> (Self, Self)
855 recommends
856 self.inv(),
857 offset % PAGE_SIZE == 0,
858 0 < offset < self.size(),
859 {
860 let at = (self.start_paddr() + offset) as usize;
861 let idx = at / PAGE_SIZE;
862 (
863 Self { range: self.start_paddr()..at, _marker: core::marker::PhantomData },
864 Self { range: at..self.end_paddr(), _marker: core::marker::PhantomData },
865 )
866 }
867}
868
869pub type SegmentIteratorItem<M> = (Frame<M>, Tracked<DropObligation<int>>);
871
872#[verifier::reject_recursive_types(T)]
875pub tracked struct SegmentIteratorProphecySeq<T> {
876 tracked var: ProphecyGhost<Seq<T>>,
877 ghost done: bool,
878}
879
880impl<T> SegmentIteratorProphecySeq<T> {
881 #[verifier::prophetic]
882 closed spec fn seq(&self) -> Seq<T> {
883 if self.done {
884 Seq::empty()
885 } else {
886 self.var.value()
887 }
888 }
889
890 proof fn new() -> (tracked res: Self)
891 ensures
892 !res.done,
893 {
894 SegmentIteratorProphecySeq { var: ProphecyGhost::new(), done: false }
895 }
896
897 proof fn resolve_cons(tracked &mut self, value: T)
898 requires
899 !old(self).done,
900 ensures
901 !final(self).done,
902 old(self).seq() == seq![value] + final(self).seq(),
903 {
904 let tracked mut var = ProphecyGhost::new();
905 tracked_swap(&mut var, &mut self.var);
906 var.resolve_dependent(&self.var, |tail| seq![value] + tail);
907 }
908
909 proof fn resolve_nil(tracked &mut self)
910 ensures
911 old(self).seq() == Seq::<T>::empty(),
912 final(self).seq() == Seq::<T>::empty(),
913 final(self).done,
914 {
915 if !self.done {
916 let tracked mut var = ProphecyGhost::new();
917 tracked_swap(&mut var, &mut self.var);
918 var.resolve(seq![]);
919 self.done = true;
920 }
921 }
922}
923
924#[verifier::reject_recursive_types(M)]
929pub struct SegmentIterator<'a, M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> {
930 segment: &'a Segment<M>,
931 range: Range<Paddr>,
932 tracked_regions: Tracked<&'a mut MetaRegionOwners>,
933 tracked_remaining: Tracked<SegmentIteratorProphecySeq<SegmentIteratorItem<M>>>,
934}
935
936#[verus_verify]
937impl<'a, M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> SegmentIterator<'a, M> {
938 pub closed spec fn segment_ref(&self) -> &'a Segment<M> {
939 self.segment
940 }
941
942 pub closed spec fn range_spec(&self) -> Range<Paddr> {
943 self.range
944 }
945
946 pub closed spec fn current_segment(&self) -> Segment<M> {
947 Segment { range: self.range.start..self.range.end, _marker: core::marker::PhantomData::<M> }
948 }
949
950 #[verifier::prophetic]
951 pub closed spec fn remaining_spec(&self) -> Seq<SegmentIteratorItem<M>> {
952 self.tracked_remaining@.seq()
953 }
954
955 #[verifier::type_invariant]
956 pub closed spec fn type_inv(self) -> bool {
957 &&& self.segment.inv()
958 &&& self.segment.range.start <= self.range.start
959 &&& self.range.end == self.segment.range.end
960 &&& self.current_segment().invariants(*self.tracked_regions@)
961 &&& self.range.start < self.range.end ==> !self.tracked_remaining@.done
962 }
963
964 #[verus_spec(res =>
965 with
966 Tracked(regions): Tracked<&'a mut MetaRegionOwners>,
967 requires
968 segment.invariants(*regions),
969 ensures
970 res.segment_ref() == segment,
971 res.range_spec() == segment.range,
972 IteratorSpec::decrease(&res) is Some,
973 IteratorSpec::initial_value_relation(&res, &res),
974 )]
975 pub fn new(segment: &'a Segment<M>) -> Self {
976 Self {
977 segment,
978 range: segment.range.start..segment.range.end,
979 tracked_regions: Tracked(regions),
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(remaining): Tracked<&mut SegmentIteratorProphecySeq<SegmentIteratorItem<M>>>,
1016 requires
1017 segment.inv(),
1018 segment.range.start <= old(range).start,
1019 old(range).end == segment.range.end,
1020 (Segment {
1021 range: old(range).start..old(range).end,
1022 _marker: core::marker::PhantomData::<M>,
1023 }).invariants(**old(regions_ref)),
1024 old(range).start < old(range).end ==> !old(remaining).done,
1025 ensures
1026 segment.inv(),
1027 segment.range.start <= final(range).start,
1028 final(range).end == segment.range.end,
1029 (Segment {
1030 range: final(range).start..final(range).end,
1031 _marker: core::marker::PhantomData::<M>,
1032 }).invariants(**final(regions_ref)),
1033 final(range).start < final(range).end ==> !final(remaining).done,
1034 match res {
1035 None => {
1036 &&& final(range).start == old(range).start
1037 &&& final(range).end == old(range).end
1038 &&& old(remaining).seq() == Seq::<SegmentIteratorItem<M>>::empty()
1039 &&& final(remaining).seq() == Seq::<SegmentIteratorItem<M>>::empty()
1040 },
1041 Some(item) => {
1042 &&& final(range).start == old(range).start + PAGE_SIZE
1043 &&& final(range).end == old(range).end
1044 &&& item.0.paddr() == old(range).start
1045 &&& old(remaining).seq() == seq![item] + final(remaining).seq()
1046 },
1047 },
1048 no_unwind
1049 )]
1050 fn next_inner(segment: &'a Segment<M>, range: &mut Range<Paddr>) -> (res: Option<
1051 SegmentIteratorItem<M>,
1052 >) {
1053 if range.start < range.end {
1054 let ghost old_remaining = remaining.seq();
1055 let ghost old_range = range.start..range.end;
1056 let ghost old_segment = Segment {
1057 range: old_range.start..old_range.end,
1058 _marker: core::marker::PhantomData::<M>,
1059 };
1060 let ghost old_regions = **regions_ref;
1061 let paddr = range.start;
1062
1063 proof {
1064 old_segment.relate_regions_at(old_regions, 0);
1065 assert(paddr == old_range.start);
1066 }
1067
1068 proof_decl! {
1069 let tracked from_raw_obl: DropObligation<int>;
1070 }
1071 let frame = unsafe {
1072 #[verus_spec(with Tracked(*regions_ref) => Tracked(from_raw_obl))]
1073 Frame::<M>::from_raw(paddr)
1074 };
1075
1076 proof {
1077 let new_range = ((old_range.start + PAGE_SIZE) as usize)..old_range.end;
1078 let ghost new_segment = Segment {
1079 range: new_range.start..new_range.end,
1080 _marker: core::marker::PhantomData::<M>,
1081 };
1082 let tracked redeem_tok = DropObligation::tracked_mint(frame.index());
1083 (*regions_ref).tracked_redeem_frame_obligation(redeem_tok);
1084 assert((**regions_ref).frame_obligations == old_regions.frame_obligations);
1085
1086 assert forall|i: int|
1087 #![trigger frame_to_index((new_segment.range.start + i * PAGE_SIZE) as usize)]
1088 0 <= i < crate::specs::mm::frame::segment::seg_nframes(
1089 new_segment.range,
1090 ) implies {
1091 let idx = frame_to_index((new_segment.range.start + i * PAGE_SIZE) as usize);
1092 &&& (**regions_ref).frame_obligations.count(idx) >= 1
1093 &&& (**regions_ref).slot_owners.contains_key(idx)
1094 &&& (**regions_ref).slots.contains_key(idx)
1095 &&& (**regions_ref).slot_owners[idx].slot_vaddr == index_to_meta(idx)
1096 &&& (**regions_ref).slot_owners[idx].inner_perms.ref_count.value() > 0
1097 &&& (**regions_ref).slot_owners[idx].inner_perms.ref_count.value()
1098 <= crate::mm::frame::meta::REF_COUNT_MAX
1099 &&& (**regions_ref).slot_owners[idx].paths_in_pt.is_empty()
1100 &&& (**regions_ref).slot_owners[idx].usage is Frame
1101 } by {
1102 old_segment.relate_regions_at(old_regions, i + 1);
1103 old_segment.relate_regions_distinct(old_regions, 0, i + 1);
1104 }
1105 assert forall|i: int, j: int|
1106 #![trigger frame_to_index((new_segment.range.start + i * PAGE_SIZE) as usize),
1107 frame_to_index((new_segment.range.start + j * PAGE_SIZE) as usize)]
1108 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
1109 new_segment.range,
1110 ) implies frame_to_index((new_segment.range.start + i * PAGE_SIZE) as usize)
1111 != frame_to_index((new_segment.range.start + j * PAGE_SIZE) as usize) by {
1112 old_segment.relate_regions_distinct(old_regions, i + 1, j + 1);
1113 }
1114 broadcast use group_page_meta;
1115
1116 assert((**regions_ref).slots[frame.index()].pptr() == frame.ptr);
1117 assert(frame.wf_with_region(**regions_ref));
1118 }
1119
1120 range.start = range.start + PAGE_SIZE;
1121 let item = (frame, Tracked(from_raw_obl));
1122 proof {
1123 remaining.resolve_cons(item);
1124 broadcast use vstd::seq::group_seq_lemmas;
1125
1126 assert(remaining.seq() == old_remaining.drop_first());
1127 assert(item == old_remaining[0]);
1128 }
1129 Some(item)
1130 } else {
1131 let ghost old_remaining = remaining.seq();
1132 proof {
1133 remaining.resolve_nil();
1134 assert(remaining.seq() == old_remaining);
1135 }
1136 None
1137 }
1138 }
1139}
1140
1141impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> IteratorSpecImpl for SegmentIterator<
1142 '_,
1143 M,
1144> {
1145 open spec fn obeys_prophetic_iter_laws(&self) -> bool {
1146 true
1147 }
1148
1149 #[verifier::prophetic]
1150 closed spec fn remaining(&self) -> Seq<Self::Item> {
1151 self.remaining_spec()
1152 }
1153
1154 #[verifier::prophetic]
1155 closed spec fn will_return_none(&self) -> bool {
1156 true
1157 }
1158
1159 closed spec fn decrease(&self) -> Option<nat> {
1160 Some((self.range.end - self.range.start) as nat)
1161 }
1162
1163 #[verifier::prophetic]
1164 open spec fn initial_value_relation(&self, init: &Self) -> bool {
1165 &&& IteratorSpec::remaining(init) == IteratorSpec::remaining(self)
1166 &&& init.remaining_spec() == self.remaining_spec()
1167 &&& init.segment_ref() == self.segment_ref()
1168 &&& init.range_spec() == self.range_spec()
1169 }
1170
1171 open spec fn peek(&self, index: int) -> Option<Self::Item> {
1172 None
1173 }
1174}
1175
1176impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Iterator for SegmentIterator<'_, M> {
1177 type Item = SegmentIteratorItem<M>;
1178
1179 fn next(&mut self) -> Option<Self::Item> {
1181 proof {
1182 use_type_invariant(&*self);
1183 }
1184
1185 #[verus_spec(with
1186 Tracked(self.tracked_regions.borrow_mut()),
1187 Tracked(self.tracked_remaining.borrow_mut()),
1188 )]
1189 SegmentIterator::next_inner(self.segment, &mut self.range)
1190 }
1191}
1192
1193#[verus_verify]
1194impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> From<Frame<M>> for Segment<M> {
1195 #[verifier::external_body]
1204 fn from(frame: Frame<M>) -> Self {
1205 let pa = frame.start_paddr();
1206 let _ = core::mem::ManuallyDrop::new(frame);
1207 Self { range: pa..(pa + PAGE_SIZE), _marker: core::marker::PhantomData }
1208 }
1209}
1210
1211impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Iterator for Segment<M> {
1212 type Item = Frame<M>;
1213
1214 #[verifier::external_body]
1221 fn next(&mut self) -> Option<Self::Item> {
1222 if self.range.start < self.range.end {
1223 let frame = unsafe { Frame::<M>::from_raw(self.range.start) };
1226 self.range.start = self.range.start + PAGE_SIZE;
1227 Some(frame)
1228 } else {
1229 None
1230 }
1231 }
1232}
1233
1234impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Segment<M> {
1235 #[verus_spec(
1244 with Tracked(regions): Tracked<&mut MetaRegionOwners>
1245 requires
1246 self.invariants(*old(regions)),
1247 forall|i: int|
1248 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1249 0 <= i < crate::specs::mm::frame::segment::seg_nframes(self.range) ==> {
1250 let idx = frame_to_index((self.range.start + i * PAGE_SIZE) as usize);
1251 old(regions).slot_owners[idx].inner_perms.ref_count.value() == 1 ==> {
1252 &&& old(regions).slot_owners[idx].inner_perms.storage.is_init()
1253 &&& old(regions).slot_owners[idx].inner_perms.in_list.value() == 0
1254 }
1255 },
1256 ensures
1257 final(regions).inv(),
1258 )]
1259 pub fn drop(self) {
1260 let ghost n = crate::specs::mm::frame::segment::seg_nframes(self.range);
1261 let mut paddr = self.range.start;
1262
1263 let ghost mut k: int = 0;
1264
1265 assert forall|i: int| #![trigger frame_idx_at(self.range.start, i)] 0 <= i < n implies {
1266 let idx = frame_idx_at(self.range.start, i);
1267 old(regions).slot_owners[idx].inner_perms.ref_count.value() == 1 ==> {
1268 &&& old(regions).slot_owners[idx].inner_perms.storage.is_init()
1269 &&& old(regions).slot_owners[idx].inner_perms.in_list.value() == 0
1270 }
1271 } by {};
1272
1273 proof {
1274 assert forall|i: int|
1275 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1276 0 <= i < n implies old(regions).frame_obligations.count(
1277 frame_to_index((self.range.start + i * PAGE_SIZE) as usize),
1278 ) >= 1 by {
1279 self.relate_regions_at(*old(regions), i);
1280 };
1281 assert forall|i: int, j: int|
1282 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize),
1283 frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1284 0 <= i < j < n implies frame_to_index((self.range.start + i * PAGE_SIZE) as usize)
1285 != frame_to_index((self.range.start + j * PAGE_SIZE) as usize) by {
1286 self.relate_regions_distinct(*old(regions), i, j);
1287 };
1288 crate::specs::mm::frame::segment::tracked_redeem_seg_obligations(
1289 regions,
1290 self.range.start,
1291 n,
1292 );
1293 }
1294
1295 loop
1296 invariant
1297 regions.inv(),
1298 self.inv(),
1299 self.range.start <= paddr <= self.range.end,
1300 paddr == (self.range.start + k * PAGE_SIZE) as usize,
1301 paddr % PAGE_SIZE == 0,
1302 paddr <= MAX_PADDR,
1303 0 <= k <= n,
1304 n == (self.range.end - self.range.start) / PAGE_SIZE as int,
1305 paddr < self.range.end <==> k < n,
1306 forall|j: int|
1307 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1308 k <= j < n ==> {
1309 let idx = frame_to_index((self.range.start + j * PAGE_SIZE) as usize);
1310 &&& regions.slot_owners.contains_key(idx)
1311 &&& regions.slots.contains_key(idx)
1312 &&& regions.slot_owners[idx] == old(regions).slot_owners[idx]
1313 },
1314 forall|j: int|
1315 #![trigger frame_idx_at(self.range.start, j)]
1316 k <= j < n ==> regions.slot_owners.contains_key(
1317 frame_idx_at(self.range.start, j),
1318 ) && regions.slot_owners[frame_idx_at(self.range.start, j)] == old(
1319 regions,
1320 ).slot_owners[frame_idx_at(self.range.start, j)],
1321 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
1322 self.invariants(*old(regions)),
1323 forall|i: int|
1324 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1325 0 <= i < n ==> {
1326 let idx = frame_to_index((self.range.start + i * PAGE_SIZE) as usize);
1327 old(regions).slot_owners[idx].inner_perms.ref_count.value() == 1 ==> {
1328 &&& old(regions).slot_owners[idx].inner_perms.storage.is_init()
1329 &&& old(regions).slot_owners[idx].inner_perms.in_list.value() == 0
1330 }
1331 },
1332 decreases n - k,
1333 {
1334 if paddr >= self.range.end {
1335 break;
1336 }
1337 proof {
1338 self.relate_regions_at(*old(regions), k);
1339 }
1340
1341 proof_decl! {
1342 let tracked from_raw_obl: vstd_extra::drop_tracking::DropObligation<int>;
1343 }
1344
1345 let frame = unsafe {
1351 #[verus_spec(with Tracked(regions) => Tracked(from_raw_obl))]
1352 Frame::<M>::from_raw(paddr)
1353 };
1354
1355 frame.drop(Tracked(regions), Tracked(from_raw_obl));
1356
1357 proof {
1358 assert forall|j: int|
1359 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1360 (k + 1) <= j < n implies {
1361 let idx = frame_to_index((self.range.start + j * PAGE_SIZE) as usize);
1362 &&& regions.slot_owners.contains_key(idx)
1363 &&& regions.slots.contains_key(idx)
1364 &&& regions.slot_owners[idx] == old(regions).slot_owners[idx]
1365 } by {
1366 self.relate_regions_distinct(*old(regions), k, j);
1367 };
1368 }
1369
1370 paddr = paddr + PAGE_SIZE;
1371
1372 proof {
1373 k = k + 1;
1374 }
1375 }
1376 }
1377}
1378
1379impl<M: AnyFrameMeta + ?Sized> Inv for Segment<M> {
1486 open spec fn inv(self) -> bool {
1491 &&& self.start_paddr() % PAGE_SIZE == 0
1492 &&& self.end_paddr() % PAGE_SIZE == 0
1493 &&& self.start_paddr() <= self.end_paddr() <= MAX_PADDR
1494 }
1495}
1496
1497}