1use vstd::prelude::*;
4use vstd_extra::seq_extra::{seq_tracked_map_values, seq_tracked_subrange};
5
6use core::{fmt::Debug, ops::Range};
7
8use crate::mm::frame::{inc_frame_ref_count, untyped::AnyUFrameMeta, Frame};
9
10use vstd_extra::cast_ptr::*;
11use vstd_extra::cast_ptr::*;
12use vstd_extra::ownership::*;
13
14use super::meta::mapping::{frame_to_index, frame_to_index_spec, frame_to_meta, meta_addr};
15use super::{AnyFrameMeta, GetFrameError, MetaPerm, MetaSlot};
16use crate::mm::{Paddr, PagingLevel, Vaddr};
17use crate::specs::arch::mm::{MAX_NR_PAGES, MAX_PADDR, PAGE_SIZE};
18use crate::specs::mm::frame::meta_owners::*;
19use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
20use vstd_extra::drop_tracking::*;
21
22verus! {
23
24#[repr(transparent)]
37pub struct Segment<M: AnyFrameMeta + ?Sized> {
38 pub range: Range<Paddr>,
40 pub _marker: core::marker::PhantomData<M>,
42}
43
44impl<M: AnyFrameMeta + ?Sized> TrackDrop for Segment<M> {
46 type State = MetaRegionOwners;
47
48 open spec fn constructor_requires(self, s: Self::State) -> bool {
49 true
50 }
51
52 open spec fn constructor_ensures(self, s0: Self::State, s1: Self::State) -> bool {
53 s0 =~= s1
54 }
55
56 proof fn constructor_spec(self, tracked s: &mut Self::State) {
57 admit()
58 }
59
60 open spec fn drop_requires(self, s: Self::State) -> bool {
61 true
62 }
63
64 open spec fn drop_ensures(self, s0: Self::State, s1: Self::State) -> bool {
65 s0 =~= s1
66 }
67
68 proof fn drop_spec(self, tracked s: &mut Self::State) {
69 admit()
70 }
71}
72
73pub tracked struct SegmentOwner<M: AnyFrameMeta + ?Sized> {
76 pub perms: Seq<MetaPerm<M>>,
78}
79
80impl<M: AnyFrameMeta + ?Sized> Inv for Segment<M> {
81 open spec fn inv(self) -> bool {
86 &&& self.range.start % PAGE_SIZE == 0
87 &&& self.range.end % PAGE_SIZE == 0
88 &&& self.range.start <= self.range.end < MAX_PADDR
89 }
90}
91
92impl<M: AnyFrameMeta + ?Sized> Inv for SegmentOwner<M> {
93 open spec fn inv(self) -> bool {
98 &&& forall|i: int|
99 #![trigger self.perms[i]]
100 0 <= i < self.perms.len() as int ==> {
101 &&& self.perms[i].addr() % PAGE_SIZE == 0
102 &&& self.perms[i].addr() < MAX_PADDR
103 &&& self.perms[i].wf(&self.perms[i].inner_perms)
104 &&& self.perms[i].is_init()
105 }
106 }
107}
108
109impl<M: AnyFrameMeta + ?Sized> Segment<M> {
110 pub open spec fn inv_with(&self, owner: &SegmentOwner<M>) -> bool {
118 &&& self.inv()
119 &&& owner.perms.len() * PAGE_SIZE == self.range.end - self.range.start
120 &&& forall|i: int|
121 #![trigger owner.perms[i]]
122 0 <= i < owner.perms.len() as int ==> owner.perms[i].addr() == meta_addr(
123 frame_to_index((self.range.start + i * PAGE_SIZE) as usize),
124 )
125 }
126}
127
128pub type USegment = Segment<dyn AnyUFrameMeta>;
136
137#[verus_verify]
138impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Segment<M> {
139 #[verifier::inline]
141 pub open spec fn start_paddr_spec(&self) -> Paddr
142 recommends
143 self.inv(),
144 {
145 self.range.start
146 }
147
148 #[verifier::inline]
150 pub open spec fn end_paddr_spec(&self) -> Paddr
151 recommends
152 self.inv(),
153 {
154 self.range.end
155 }
156
157 #[verifier::inline]
159 pub open spec fn size_spec(&self) -> usize
160 recommends
161 self.inv(),
162 {
163 (self.range.end - self.range.start) as usize
164 }
165
166 #[verifier::inline]
168 pub open spec fn nrpage_spec(&self) -> usize
169 recommends
170 self.inv(),
171 {
172 self.size_spec() / PAGE_SIZE
173 }
174
175 pub open spec fn split_spec(self, offset: usize) -> (Self, Self)
177 recommends
178 self.inv(),
179 offset % PAGE_SIZE == 0,
180 0 < offset < self.size_spec(),
181 {
182 let at = (self.range.start + offset) as usize;
183 let idx = at / PAGE_SIZE;
184 (
185 Self { range: self.range.start..at, _marker: core::marker::PhantomData },
186 Self { range: at..self.range.end, _marker: core::marker::PhantomData },
187 )
188 }
189
190 #[inline(always)]
192 #[verifier::when_used_as_spec(start_paddr_spec)]
193 pub fn start_paddr(&self) -> (res: Paddr)
194 requires
195 self.inv(),
196 returns
197 self.start_paddr_spec(),
198 {
199 self.range.start
200 }
201
202 #[inline(always)]
204 #[verifier::when_used_as_spec(end_paddr_spec)]
205 pub fn end_paddr(&self) -> (res: Paddr)
206 requires
207 self.inv(),
208 returns
209 self.end_paddr_spec(),
210 {
211 self.range.end
212 }
213
214 #[inline(always)]
216 #[verifier::when_used_as_spec(size_spec)]
217 pub fn size(&self) -> (res: usize)
218 requires
219 self.inv(),
220 returns
221 self.size_spec(),
222 {
223 self.range.end - self.range.start
224 }
225
226 pub open spec fn from_unused_requires(
233 regions: MetaRegionOwners,
234 range: Range<Paddr>,
235 metadata_fn: impl Fn(Paddr) -> (Paddr, M),
236 ) -> bool {
237 &&& regions.inv()
238 &&& range.start % PAGE_SIZE == 0
239 &&& range.end % PAGE_SIZE == 0
240 &&& range.start <= range.end < MAX_PADDR
241 &&& forall|paddr_in: Paddr|
242 (range.start <= paddr_in < range.end && paddr_in % PAGE_SIZE == 0) ==> {
243 &&& metadata_fn.requires((paddr_in,))
244 }
245 &&& forall|paddr_in: Paddr, paddr_out: Paddr, m: M|
246 metadata_fn.ensures((paddr_in,), (paddr_out, m)) ==> {
247 &&& paddr_out < MAX_PADDR
248 &&& paddr_out % PAGE_SIZE == 0
249 &&& paddr_in == paddr_out
250 &&& regions.slots.contains_key(frame_to_index(paddr_out))
251 &&& regions.slot_owners[frame_to_index(paddr_out)].usage is Unused
252 &&& regions.slot_owners[frame_to_index(paddr_out)].inner_perms.in_list.points_to(0)
253 }
254 }
255
256 pub open spec fn from_unused_ensures(
262 old_regions: MetaRegionOwners,
263 new_regions: MetaRegionOwners,
264 owner: Option<SegmentOwner<M>>,
265 range: Range<Paddr>,
266 metadata_fn: impl Fn(Paddr) -> (Paddr, M),
267 r: Result<Self, GetFrameError>,
268 ) -> bool {
269 &&& r matches Ok(r) ==> {
270 &&& new_regions.inv()
271 &&& r.range.start == range.start
272 &&& r.range.end == range.end
273 &&& owner matches Some(owner) && {
274 &&& r.inv_with(&owner)
275 &&& forall|i: int|
276 #![trigger owner.perms[i]]
277 0 <= i < owner.perms.len() as int ==> {
278 &&& owner.perms[i].addr() == meta_addr(
279 frame_to_index_spec((range.start + i * PAGE_SIZE) as usize),
280 )
281 }
282 &&& forall|paddr: Paddr|
283 #![trigger frame_to_index_spec(paddr)]
284 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
285 ==> !new_regions.slots.contains_key(frame_to_index_spec(paddr))
286 }
287 }
288 }
289
290 pub open spec fn split_requires(self, owner: SegmentOwner<M>, offset: usize) -> bool {
295 &&& self.inv_with(&owner)
296 &&& offset % PAGE_SIZE == 0
297 &&& 0 < offset < self.size()
298 }
299
300 pub open spec fn split_ensures(
306 self,
307 offset: usize,
308 lhs: Self,
309 rhs: Self,
310 ori_owner: SegmentOwner<M>,
311 lhs_owner: SegmentOwner<M>,
312 rhs_owner: SegmentOwner<M>,
313 ) -> bool {
314 &&& lhs.inv_with(&lhs_owner)
315 &&& rhs.inv_with(&rhs_owner)
316 &&& (lhs, rhs) == self.split_spec(offset)
317 &&& ori_owner.perms =~= (lhs_owner.perms + rhs_owner.perms)
318 }
319
320 pub open spec fn into_raw_requires(
325 self,
326 regions: MetaRegionOwners,
327 owner: SegmentOwner<M>,
328 ) -> bool {
329 &&& self.inv_with(&owner)
330 &&& regions.inv()
331 &&& owner.inv()
332 }
333
334 pub open spec fn into_raw_ensures(
339 self,
340 old_regions: MetaRegionOwners,
341 regions: MetaRegionOwners,
342 r: Range<Paddr>,
343 ) -> bool {
344 &&& r == self.range
345 &&& regions.inv()
346 &&& regions =~= old_regions
347 }
348
349 pub open spec fn from_raw_requires(
355 regions: MetaRegionOwners,
356 range: Range<Paddr>,
357 owner: SegmentOwner<M>,
358 ) -> bool {
359 &&& regions.inv()
360 &&& range.start % PAGE_SIZE == 0
361 &&& range.end % PAGE_SIZE == 0
362 &&& range.start < range.end < MAX_PADDR
363 }
364
365 pub open spec fn from_raw_ensures(
370 self,
371 old_regions: MetaRegionOwners,
372 new_regions: MetaRegionOwners,
373 owner: SegmentOwner<M>,
374 range: Range<Paddr>,
375 ) -> bool {
376 &&& self.range == range
377 &&& new_regions.inv()
378 &&& new_regions =~= old_regions
379 }
380
381 pub open spec fn slice_requires(self, owner: SegmentOwner<M>, range: Range<Paddr>) -> bool {
386 &&& self.inv_with(&owner)
387 &&& range.start % PAGE_SIZE == 0
388 &&& range.end % PAGE_SIZE == 0
389 &&& self.range.start + range.start <= self.range.start + range.end <= self.range.end
390 }
391
392 pub open spec fn slice_ensures(
399 self,
400 owner: SegmentOwner<M>,
401 range: Range<Paddr>,
402 res: Self,
403 ) -> bool {
404 &&& res.inv_with(
405 &SegmentOwner {
406 perms: owner.perms.subrange(
407 (range.start / PAGE_SIZE) as int,
408 (range.end / PAGE_SIZE) as int,
409 ),
410 },
411 )
412 }
413
414 pub open spec fn next_requires(
420 self,
421 regions: MetaRegionOwners,
422 owner: SegmentOwner<M>,
423 ) -> bool {
424 &&& self.inv()
425 &&& regions.inv()
426 &&& owner.perms.len() > 0
427 &&& !regions.slots.contains_key(frame_to_index(self.range.start))
428 &&& regions.slot_owners.contains_key(frame_to_index(self.range.start))
429 &&& regions.slot_owners[frame_to_index(self.range.start)].raw_count == 1
430 &&& regions.slot_owners[frame_to_index(self.range.start)].self_addr == frame_to_meta(
431 self.range.start,
432 )
433 &&& owner.perms[0].points_to.is_init()
434 &&& owner.perms[0].points_to.addr() == frame_to_meta(self.range.start)
435 &&& owner.perms[0].points_to.value().wf(
436 regions.slot_owners[frame_to_index(self.range.start)],
437 )
438 }
439
440 pub open spec fn next_ensures(
446 old_self: Self,
447 new_self: Self,
448 old_regions: MetaRegionOwners,
449 new_regions: MetaRegionOwners,
450 res: Option<Frame<M>>,
451 ) -> bool {
452 &&& new_regions.inv()
453 &&& new_self.inv()
454 &&& match res {
455 None => { &&& new_self.range.start == old_self.range.end },
456 Some(f) => {
457 &&& new_self.range.start == old_self.range.start + PAGE_SIZE
458 &&& f.paddr() == old_self.range.start
459 &&& new_regions.slots.contains_key(frame_to_index(f.paddr()))
460 &&& new_regions.slot_owners[frame_to_index(f.paddr())].raw_count == 0
461 },
462 }
463 }
464
465 #[verus_spec(r =>
480 with
481 Tracked(regions): Tracked<&mut MetaRegionOwners>,
482 -> owner: Tracked<Option<SegmentOwner<M>>>,
483 requires
484 Self::from_unused_requires(*old(regions), range, metadata_fn),
485 ensures
486 Self::from_unused_ensures(*old(regions), *regions, owner@, range, metadata_fn, r),
487 )]
488 pub fn from_unused(range: Range<Paddr>, metadata_fn: impl Fn(Paddr) -> (Paddr, M)) -> (res:
489 Result<Self, GetFrameError>) {
490 proof_decl! {
491 let tracked mut owner: Option<SegmentOwner<M>> = None;
492 let tracked mut addrs = Seq::<usize>::tracked_empty();
493 let tracked mut perms = Seq::<MetaPerm<M>>::tracked_empty();
494 }
495 let mut segment = Self {
498 range: range.start..range.start,
499 _marker: core::marker::PhantomData,
500 };
501
502 let mut i = 0;
503 let addr_len = (range.end - range.start) / PAGE_SIZE;
504
505 #[verus_spec(
506 invariant
507 i <= addr_len,
508 i as int == addrs.len(),
509 i as int == perms.len(),
510 range.start % PAGE_SIZE == 0,
511 range.end % PAGE_SIZE == 0,
512 range.start <= range.start + i * PAGE_SIZE <= range.end,
513 range.end == range.start + addr_len * PAGE_SIZE,
514 addr_len == (range.end - range.start) / PAGE_SIZE as int,
515 i <= addr_len,
516 forall|paddr_in: Paddr|
517 (range.start + i * PAGE_SIZE <= paddr_in < range.end && paddr_in % PAGE_SIZE == 0) ==> {
518 &&& metadata_fn.requires((paddr_in,))
519 },
520 forall|paddr_in: Paddr, paddr_out: Paddr, m: M|
521 range.start + i * PAGE_SIZE <= paddr_in < range.end
522 && paddr_in % PAGE_SIZE == 0
523 && metadata_fn.ensures((paddr_in,), (paddr_out, m)) ==> {
524 &&& paddr_out < MAX_PADDR
525 &&& paddr_out % PAGE_SIZE == 0
526 &&& paddr_in == paddr_out
527 &&& regions.slots.contains_key(frame_to_index(paddr_out))
528 &&& regions.slot_owners[frame_to_index(paddr_out)].usage is Unused
529 &&& regions.slot_owners[frame_to_index(paddr_out)].inner_perms.in_list.points_to(0)
530 },
531 forall|j: int|
532 0 <= j < addrs.len() as int ==> {
533 &&& !regions.slots.contains_key(frame_to_index_spec(addrs[j]))
534 &&& addrs[j] % PAGE_SIZE == 0
535 &&& addrs[j] < MAX_PADDR
536 &&& addrs[j] == range.start + (j as u64) * PAGE_SIZE
537 },
538 forall|j: int|
539 #![trigger perms[j]]
540 0 <= j < perms.len() as int ==> {
541 &&& perms[j].addr() == frame_to_meta(addrs[j])
542 &&& perms[j].wf(&perms[j].inner_perms)
543 &&& perms[j].is_init()
544 },
545 regions.inv(),
546 segment.range.start == range.start,
547 segment.range.end == range.start + i * PAGE_SIZE,
548 decreases addr_len - i,
549 )]
550 while i < addr_len {
551 let paddr_in = range.start + i * PAGE_SIZE;
552 let (paddr, meta) = metadata_fn(paddr_in);
553
554 let (frame, Tracked(frame_perm)) = match #[verus_spec(with Tracked(regions))]
555 MetaSlot::get_from_unused(paddr, meta, false) {
556 Ok(res) => {
557 let (ptr, Tracked(frame_perm)) = res;
558 (Frame { ptr, _marker: core::marker::PhantomData::<M> }, Tracked(frame_perm))
559 },
560 Err(e) => {
561 return {
562 proof_with!(|= Tracked(owner));
563 Err(e)
564 };
565 },
566 };
567
568 proof {
569 assert(metadata_fn.ensures((paddr_in,), (paddr, meta)));
570 assert(frame_perm.addr() == frame_to_meta(paddr));
571 assert(frame_perm.wf(&frame_perm.inner_perms));
572 assert(frame_perm.is_init());
573 assert(frame.constructor_requires(*regions)) by {};
574 perms.tracked_push(frame_perm);
575 }
576
577 let _ = ManuallyDrop::new(frame, Tracked(regions));
578 segment.range.end = paddr + PAGE_SIZE;
579 proof {
580 addrs.tracked_push(paddr);
581 }
582
583 i += 1;
584 }
585
586 proof {
587 broadcast use vstd_extra::seq_extra::lemma_seq_to_set_map_contains;
588
589 owner = Some(SegmentOwner { perms });
590
591 assert forall|addr: usize|
592 #![trigger frame_to_index_spec(addr)]
593 range.start <= addr < range.end && addr % PAGE_SIZE == 0 implies {
594 &&& !regions.slots.contains_key(frame_to_index_spec(addr))
595 } by {
596 assert(addrs.contains(addr)) by {
598 if !addrs.contains(addr) {
599 let j = (addr - range.start) / PAGE_SIZE as int;
600 assert(0 <= j < addrs.len() as usize) by {
601 assert(addr >= range.start);
602 assert(addr < range.end);
603 assert(addr % PAGE_SIZE == 0);
604 };
605 assert(addrs[j as int] == addr);
606 }
607 }
608 }
609 }
610
611 proof_with!(|= Tracked(owner));
612 Ok(segment)
613 }
614
615 #[verus_spec(r =>
627 with
628 Tracked(owner): Tracked<SegmentOwner<M>>,
629 Tracked(regions): Tracked<&mut MetaRegionOwners>,
630 -> frame_perms: (Tracked<SegmentOwner<M>>, Tracked<SegmentOwner<M>>),
631 requires
632 Self::split_requires(self, owner, offset),
633 ensures
634 Self::split_ensures(self, offset, r.0, r.1, owner, frame_perms.0@, frame_perms.1@),
635 )]
636 pub fn split(self, offset: usize) -> (Self, Self) {
637 let at = self.range.start + offset;
638 let idx = offset / PAGE_SIZE;
639 let res = (
640 Self { range: self.range.start..at, _marker: core::marker::PhantomData },
641 Self { range: at..self.range.end, _marker: core::marker::PhantomData },
642 );
643
644 let _ = ManuallyDrop::new(self, Tracked(regions));
645
646 let tracked frame_perms1 = SegmentOwner {
647 perms: seq_tracked_subrange(owner.perms, 0, idx as int),
648 };
649 let tracked frame_perms2 = SegmentOwner {
650 perms: seq_tracked_subrange(owner.perms, idx as int, owner.perms.len() as int),
651 };
652
653 proof {
654 owner.perms.lemma_split_at(idx as int);
655 }
656
657 proof_with!(|= (Tracked(frame_perms1), Tracked(frame_perms2)));
658 res
659 }
660
661 #[verus_spec(r =>
667 with
668 Tracked(regions): Tracked<&mut MetaRegionOwners>,
669 Tracked(owner): Tracked<SegmentOwner<M>>,
670 -> frame_perms: Tracked<SegmentOwner<M>>,
671 requires
672 Self::into_raw_requires(self, *old(regions), owner),
673 ensures
674 Self::into_raw_ensures(self, *old(regions), *regions, r),
675 frame_perms@ == owner,
676 )]
677 pub(crate) fn into_raw(self) -> Range<Paddr> {
678 let range = self.range.clone();
679 let _ = ManuallyDrop::new(self, Tracked(regions));
680
681 proof_with!(|= Tracked(owner));
682 range
683 }
684
685 #[verus_spec(r =>
699 with
700 Tracked(regions): Tracked<&mut MetaRegionOwners>,
701 Tracked(owner): Tracked<SegmentOwner<M>>,
702 requires
703 Self::from_raw_requires(*old(regions), range, owner),
704 ensures
705 Self::from_raw_ensures(r, *old(regions), *regions, owner, range),
706 )]
707 pub(crate) unsafe fn from_raw(range: Range<Paddr>) -> Self {
708 Self { range, _marker: core::marker::PhantomData }
709 }
710
711 #[verus_spec(r =>
726 with
727 Tracked(owner): Tracked<&SegmentOwner<M>>,
728 requires
729 Self::slice_requires(*self, *owner, *range),
730 ensures
731 Self::slice_ensures(*self, *owner, *range, r),
732 )]
733 pub fn slice(&self, range: &Range<Paddr>) -> Self {
734 let start = self.range.start + range.start;
735 let end = self.range.start + range.end;
736
737 let mut i = 0;
738 let addr_len = (end - start) / PAGE_SIZE;
739 while i < addr_len
740 invariant
741 start % PAGE_SIZE == 0,
742 end % PAGE_SIZE == 0,
743 start + i * PAGE_SIZE <= end,
744 i <= addr_len,
745 addr_len == (end - start) / PAGE_SIZE as int,
746 decreases addr_len - i,
747 {
748 let paddr = start + i * PAGE_SIZE;
749 i += 1;
754 }
755
756 Self { range: start..end, _marker: core::marker::PhantomData }
757 }
758
759 #[verus_spec(res =>
781 with
782 Tracked(regions): Tracked<&mut MetaRegionOwners>,
783 Tracked(owner): Tracked<&mut SegmentOwner<M>>
784 requires
785 Self::next_requires(*old(self), *old(regions), *old(owner)),
786 ensures
787 Self::next_ensures(*old(self), *self, *old(regions), *regions, res),
788 )]
789 pub fn next(&mut self) -> Option<Frame<M>> {
790 if self.range.start < self.range.end {
791 let tracked perm = owner.perms.tracked_remove(0);
792
793 proof_decl! {
794 let tracked from_raw_debt: crate::specs::mm::frame::frame_specs::BorrowDebt;
795 }
796
797 let frame = unsafe {
798 #[verus_spec(with Tracked(regions), Tracked(&perm) => Tracked(from_raw_debt))]
799 Frame::<M>::from_raw(self.range.start)
800 };
801
802 proof {
803 from_raw_debt.discharge_bookkeeping();
805 }
806
807 self.range.start = self.range.start + PAGE_SIZE;
808 Some(frame)
809 } else {
810 None
811 }
812 }
813}
814
815}