Skip to main content

ostd/mm/frame/
segment.rs

1// SPDX-License-Identifier: MPL-2.0
2//! A contiguous range of frames.
3use vstd::{
4    prelude::*,
5    simple_pptr::{PPtr, PointsTo},
6    std_specs::{
7        convert::FromSpecImpl,
8        iter::{IteratorSpec, IteratorSpecImpl},
9    },
10};
11use vstd_extra::{assert, cast_ptr::*, ownership::*, panic::may_panic, prelude::*};
12
13use crate::specs::{
14    arch::*,
15    mm::frame::{
16        frame_specs::FrameRawPerms, mapping::*, meta_owners::*,
17        meta_region_owners::MetaRegionOwners, segment::*,
18    },
19};
20
21use super::{
22    Frame, Paddr,
23    meta::mapping::frame_to_meta,
24    meta::{AnyFrameMeta, GetFrameError},
25};
26use crate::mm::frame::{meta::REF_COUNT_MAX, untyped::AnyUFrameMeta};
27use crate::mm::page_table::RCClone;
28use crate::mm::{PagingLevel, Vaddr, frame::MetaSlot, paddr_to_vaddr};
29use core::{fmt::Debug, mem::ManuallyDrop, ops::Range};
30
31verus! {
32
33/// A contiguous range of homogeneous physical memory frames.
34///
35/// This is a handle to multiple contiguous frames. It will be more lightweight
36/// than owning an array of frame handles.
37///
38/// The ownership is achieved by the reference counting mechanism of frames.
39/// When constructing a [`Segment`], the frame handles are created then
40/// forgotten, leaving the reference count. When dropping a it, the frame
41/// handles are restored and dropped, decrementing the reference count.
42///
43/// All the metadata of the frames are homogeneous, i.e., they are of the same
44/// type.
45// #[repr(transparent)]
46pub struct Segment<M: AnyFrameMeta + ?Sized> {
47    range: Range<Paddr>,
48    _marker: core::marker::PhantomData<M>,
49    /// One raw permission bundle for each frame in `range`, in address order.
50    #[cfg(verus_keep_ghost_body)]
51    tracked_perms: Tracked<Option<Seq<FrameRawPerms>>>,
52}
53
54/*
55impl<M: AnyFrameMeta + ?Sized> Debug for Segment<M> {
56    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
57        write!(f, "Segment({:#x}..{:#x})", self.range.start, self.range.end)
58    }
59}
60*/
61
62/*impl<M: AnyFrameMeta + ?Sized> Drop for Segment<M> {
63    fn drop(&mut self) {
64        for paddr in self.range.clone().step_by(PAGE_SIZE) {
65            // SAFETY: for each frame there would be a forgotten handle
66            // when creating the `Segment` object.
67            drop(unsafe { Frame::<M>::from_raw(paddr) });
68        }
69    }
70}*/
71
72/// A contiguous range of homogeneous untyped physical memory frames that have any metadata.
73///
74/// In other words, the metadata of the frames are of the same type, and they
75/// are untyped, but the type of metadata is not known at compile time. An
76/// [`USegment`] as a parameter accepts any untyped segments.
77///
78/// The usage of this frame will not be changed while this object is alive.
79pub type USegment = Segment<dyn AnyUFrameMeta>;
80
81/* impl<M: AnyFrameMeta + ?Sized> Clone for Segment<M> {
82    fn clone(&self) -> Self {
83        for paddr in self.range.clone().step_by(PAGE_SIZE) {
84            // SAFETY: for each frame there would be a forgotten handle
85            // when creating the `Segment` object, so we already have
86            // reference counts for the frames.
87            unsafe { inc_frame_ref_count(paddr) };
88        }
89        Self {
90            range: self.range.clone(),
91            _marker: core::marker::PhantomData,
92        }
93    }
94} */
95
96impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> RCClone for Segment<M> {
97    open spec fn clone_requires(self, perm: MetaRegionOwners) -> bool {
98        &&& self.inv()
99        &&& perm.inv()
100        &&& self.relate_regions(perm)
101        &&& forall|pa: Paddr|
102            #![trigger frame_to_index(pa)]
103            (self.start_paddr() <= pa < self.end_paddr() && pa % PAGE_SIZE == 0) ==> {
104                let idx = frame_to_index(pa);
105                &&& perm.contains(idx)
106                &&& valid_frame_paddr(pa)
107                &&& perm.ref_count(idx) > 0
108                &&& perm.ref_count(idx) + 1 < REF_COUNT_MAX
109                &&& !MetaSlot::inc_ref_count_panic_cond(perm.slot_owners[idx].ref_count_perm)
110            }
111    }
112
113    open spec fn clone_ensures(
114        self,
115        old_perm: MetaRegionOwners,
116        new_perm: MetaRegionOwners,
117        res: Self,
118    ) -> bool {
119        &&& res.range() == self.range()
120        &&& res.inv()
121        &&& new_perm.inv()
122        &&& res.relate_regions(new_perm)
123    }
124
125    #[verifier::rlimit(200)]
126    fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self) {
127        let mut paddr = self.range.start;
128        proof_decl! {
129            let tracked mut raw_perms = Seq::<FrameRawPerms>::tracked_empty();
130        }
131
132        loop
133            invariant
134                perm.inv(),
135                self.inv(),
136                self.relate_regions(*old(perm)),
137                perm.slots == old(perm).slots,
138                perm.slot_owners.dom() == old(perm).slot_owners.dom(),
139                raw_perms.len() == (paddr - self.range.start) / (PAGE_SIZE as int),
140                forall|i: int|
141                    #![trigger raw_perms[i]]
142                    0 <= i < raw_perms.len() ==> {
143                        let idx = frame_to_index((self.range.start + i * PAGE_SIZE) as usize);
144                        &&& raw_perms[i].slot_perm == perm.slots[idx]
145                        &&& raw_perms[i].inv()
146                        &&& raw_perms[i].metadata_perm.id()
147                            == perm.slot_owners[idx].metadata_perm.id()
148                    },
149                forall|i: int|
150                    #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
151                    0 <= i < raw_perms.len() ==> ({
152                        let idx = frame_to_index((self.range.start + i * PAGE_SIZE) as usize);
153                        &&& perm.contains(idx)
154                        &&& perm.slot_owners[idx].slot_vaddr == index_to_meta(idx)
155                        &&& perm.ref_count(idx) > 0
156                        &&& perm.ref_count(idx) <= REF_COUNT_MAX
157                        &&& perm.slot_owners[idx].paths_in_pt.is_empty()
158                        &&& perm.slot_owners[idx].usage
159                            == raw_perms[i].metadata_perm.resource().usage()
160                    }),
161                self.range.start <= paddr <= self.range.end,
162                paddr % PAGE_SIZE == 0,
163                paddr <= MAX_PADDR,
164                forall|pa: Paddr|
165                    #![trigger frame_to_index(pa)]
166                    (paddr <= pa < self.range.end && pa % PAGE_SIZE == 0) ==> {
167                        let idx = frame_to_index(pa);
168                        &&& perm.contains(idx)
169                        &&& valid_frame_paddr(pa)
170                        &&& perm.ref_count(idx) > 0
171                        &&& perm.ref_count(idx) + 1 < REF_COUNT_MAX
172                        &&& !MetaSlot::inc_ref_count_panic_cond(
173                            perm.slot_owners[idx].ref_count_perm,
174                        )
175                    },
176                forall|i: int|
177                    #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
178                    raw_perms.len() <= i < self.len() ==> perm.slot_owner(
179                        (self.range.start + i * PAGE_SIZE) as usize,
180                    ) == old(perm).slot_owner((self.range.start + i * PAGE_SIZE) as usize),
181            ensures
182                paddr == self.range.end,
183            decreases self.range.end - paddr,
184        {
185            if paddr >= self.range.end {
186                break;
187            }
188            let tracked_permission = unsafe {
189                #[verus_spec(with Tracked(perm))]
190                crate::mm::frame::inc_frame_ref_count(paddr)
191            };
192            let tracked frame_permission = tracked_permission.get();
193            proof {
194                frame_permission.agree(
195                    &self.tracked_perms.borrow().tracked_borrow().tracked_borrow(
196                        raw_perms.len() as int,
197                    ).metadata_perm,
198                );
199                let tracked slot_perm = perm.tracked_borrow_slot(paddr);
200                raw_perms.tracked_push(
201                    FrameRawPerms { slot_perm, metadata_perm: frame_permission },
202                );
203            }
204
205            paddr += PAGE_SIZE;
206        }
207
208        Self {
209            range: self.range.start..self.range.end,
210            _marker: core::marker::PhantomData,
211            #[cfg(verus_keep_ghost_body)]
212            tracked_perms: Tracked(Some(raw_perms)),
213        }
214    }
215}
216
217#[verus_verify]
218impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Segment<M> {
219    /// Creates a new [`Segment`] from unused frames.
220    ///
221    /// The caller must provide a closure to initialize metadata for all the frames.
222    /// The closure receives the physical address of the frame and returns the
223    /// metadata, which is similar to [`core::array::from_fn`].
224    ///
225    /// It returns an error if:
226    ///  - the physical address is invalid or not aligned;
227    ///  - any of the frames cannot be created with a specific reason.
228    ///
229    /// # Panics
230    ///
231    /// It panics if the range is empty.
232    ///
233    /// # Verified Properties
234    /// ## Preconditions
235    /// - the metadata function must be well-formed and valid for all frames in the range;
236    /// - the metadata function must ensure that the frames can be created and owned by the segment;
237    /// - for any frame created via the closure `metadata_fn`, the corresponding slot in `regions`
238    ///   must be unused and not dropped in the owner ([`MetaRegionOwners`]).
239    ///
240    /// Range constraints (alignment, `range.end <= MAX_PADDR`, non-emptiness) are runtime-checked
241    /// in the body — see the postconditions below for the corresponding error variants.
242    /// ## Postconditions
243    /// - if the result is `Ok`, the returned segment satisfies its invariant,
244    ///   relates to the updated metadata region, and has the same physical
245    ///   address range as the input;
246    /// - if the input range is misaligned, the result is `Err(NotAligned)`;
247    /// - if the input range exceeds `MAX_PADDR`, the result is `Err(OutOfBound)`;
248    /// - if the input is aligned and within `MAX_PADDR` and the function terminated,
249    ///   then `range.start < range.end` (the runtime `assert!` would otherwise diverge).
250    /// FIXME: this implementation does not match source code.
251    #[verifier::spinoff_prover]
252    #[verus_spec(r =>
253        with
254            Tracked(regions): Tracked<&mut MetaRegionOwners>,
255            Tracked(repr_perm): Tracked<&mut M::ReprPerm>,
256        requires
257            old(regions).inv(),
258            forall|paddr_in: Paddr|
259                (range.start <= paddr_in < range.end && paddr_in % PAGE_SIZE == 0) ==> {
260                    &&& metadata_fn.requires((paddr_in,))
261                },
262            forall|paddr_in: Paddr, paddr_out: Paddr, m: M|
263                metadata_fn.ensures((paddr_in,), (paddr_out, m)) ==> paddr_in == paddr_out,
264            !(range.end <= MAX_PADDR ==> range.start < range.end) ==> may_panic(),
265        ensures
266            final(regions).inv(),
267            (range.start % PAGE_SIZE != 0 || range.end % PAGE_SIZE != 0)
268                ==> r == Err::<Self, _>(GetFrameError::NotAligned),
269            (range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0 && range.end > MAX_PADDR)
270                ==> r == Err::<Self, _>(GetFrameError::OutOfBound),
271            r matches Ok(seg) ==> {
272                &&& seg.inv()
273                &&& seg.start_paddr() == range.start
274                &&& seg.end_paddr() == range.end
275                &&& seg.start_paddr() < seg.end_paddr()
276                &&& seg.relate_regions(*final(regions))
277                &&& forall|paddr: Paddr|
278                    #![trigger frame_to_index(paddr)]
279                    (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
280                        ==> final(regions).contains(frame_to_index(paddr))
281                &&& range.start < range.end <= MAX_PADDR
282            },
283    )]
284    pub fn from_unused(range: Range<Paddr>, metadata_fn: impl Fn(Paddr) -> (Paddr, M)) -> (res:
285        Result<Self, GetFrameError>) {
286        proof_decl! {
287            let tracked raw_perms = Seq::<FrameRawPerms>::tracked_empty();
288        }
289
290        if range.start % PAGE_SIZE != 0 || range.end % PAGE_SIZE != 0 {
291            return Err(GetFrameError::NotAligned);
292        }
293        if range.end > MAX_PADDR {
294            return Err(GetFrameError::OutOfBound);
295        }
296        assert!(range.start < range.end);
297
298        // Construct a segment early to recycle previously forgotten frames if
299        // the subsequent operations fails in the middle.
300
301        proof_with!{ tracked_perms: Tracked(Some(raw_perms)) }
302        let mut segment = Self {
303            range: range.start..range.start,
304            _marker: core::marker::PhantomData,
305        };
306
307        let mut i = 0;
308        let addr_len = (range.end - range.start) / PAGE_SIZE;
309
310        while i < addr_len
311            invariant
312                segment.tracked_perms@ is Some,
313                range.start % PAGE_SIZE == 0,
314                range.end % PAGE_SIZE == 0,
315                range.start < range.end <= MAX_PADDR,
316                segment.range.start == range.start,
317                i <= addr_len,
318                i == segment.tracked_perms@->0.len(),
319                range.start <= range.start + i * PAGE_SIZE <= range.end,
320                range.end == range.start + addr_len * PAGE_SIZE,
321                addr_len == (range.end - range.start) / PAGE_SIZE as int,
322                forall|paddr_in: Paddr|
323                    (range.start + i * PAGE_SIZE <= paddr_in < range.end && paddr_in % PAGE_SIZE
324                        == 0) ==> {
325                        &&& metadata_fn.requires((paddr_in,))
326                    },
327                forall|paddr_in: Paddr, paddr_out: Paddr, m: M|
328                    range.start + i * PAGE_SIZE <= paddr_in < range.end && paddr_in % PAGE_SIZE == 0
329                        && metadata_fn.ensures((paddr_in,), (paddr_out, m)) ==> paddr_in
330                        == paddr_out,
331                forall|j: int|
332                    #![trigger frame_idx_at(range.start, j)]
333                    0 <= j < i ==> {
334                        let paddr = (range.start + j * PAGE_SIZE) as usize;
335                        let idx = frame_to_index(paddr);
336                        &&& regions.contains(idx)
337                        &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
338                        &&& 0 < regions.ref_count(idx) <= REF_COUNT_MAX
339                        &&& segment.tracked_perms@->0[j].inv()
340                        &&& segment.tracked_perms@->0[j].slot_perm == regions.slots[idx]
341                        &&& segment.tracked_perms@->0[j].metadata_perm.id()
342                            == regions.slot_owners[idx].metadata_perm.id()
343                        &&& regions.slot_owners[idx].paths_in_pt.is_empty()
344                        &&& regions.slot_owners[idx].usage
345                            == segment.tracked_perms@->0[j].metadata_perm.resource().usage()
346                        &&& paddr % PAGE_SIZE == 0
347                        &&& paddr < MAX_PADDR
348                    },
349                regions.inv(),
350                regions.slot_owners.dom() == old(regions).slot_owners.dom(),
351                segment.range.end == range.start + i * PAGE_SIZE,
352            ensures
353                i == addr_len,
354            decreases addr_len - i,
355        {
356            let paddr_in = range.start + i * PAGE_SIZE;
357            let (paddr, meta) = metadata_fn(paddr_in);
358
359            let res = #[verus_spec(with Tracked(regions), Tracked(repr_perm))]
360            Frame::<M>::from_unused(paddr, meta);
361            let mut frame = match res {
362                Ok(f) => f,
363                Err(e) => {
364                    let mut p = range.start;
365                    let ghost mut k: int = 0;
366                    while p < segment.range.end
367                        invariant
368                            regions.inv(),
369                            segment.tracked_perms@ is Some,
370                            segment.tracked_perms@->0.len() == i - k,
371                            regions.slot_owners.dom() == old(regions).slot_owners.dom(),
372                            range.start % PAGE_SIZE == 0,
373                            range.end <= MAX_PADDR,
374                            segment.range.end == range.start + i * PAGE_SIZE,
375                            range.start <= p <= segment.range.end,
376                            p == range.start + k * PAGE_SIZE,
377                            p % PAGE_SIZE == 0,
378                            0 <= k <= i,
379                            forall|j: int|
380                                #![trigger frame_idx_at(range.start, j)]
381                                k <= j < i ==> {
382                                    let paddr = (range.start + j * PAGE_SIZE) as usize;
383                                    let idx = frame_to_index(paddr);
384                                    &&& regions.contains(idx)
385                                    &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
386                                    &&& 0 < regions.ref_count(idx) <= REF_COUNT_MAX
387                                    &&& segment.tracked_perms@->0[j - k].inv()
388                                    &&& segment.tracked_perms@->0[j - k].slot_perm
389                                        == regions.slots[idx]
390                                    &&& segment.tracked_perms@->0[j - k].metadata_perm.id()
391                                        == regions.slot_owners[idx].metadata_perm.id()
392                                    &&& regions.slot_owners[idx].paths_in_pt.is_empty()
393                                    &&& regions.slot_owners[idx].usage
394                                        == segment.tracked_perms@->0[j
395                                        - k].metadata_perm.resource().usage()
396                                    &&& paddr % PAGE_SIZE == 0
397                                    &&& paddr < MAX_PADDR
398                                },
399                        decreases segment.range.end - p,
400                    {
401                        proof {
402                            broadcast use group_page_meta;
403
404                            assert(frame_idx_at(range.start, k) == frame_to_index(p));
405
406                        }
407                        let tracked perm =
408                            segment.tracked_perms.tracked_borrow_mut().tracked_pop_front();
409                        let frame = unsafe {
410                            #[verus_spec(with Tracked(perm))]
411                            Frame::<M>::from_raw(p)
412                        };
413                        frame.drop(Tracked(regions));
414                        p += PAGE_SIZE;
415                        proof {
416                            k = k + 1;
417                        }
418                    }
419                    return Err(e);
420                },
421            };
422
423            proof_decl! {
424                let tracked frame_permission: FracMetadataPerm = frame.tracked_metadata_perm.tracked_take();
425                let tracked slot_perm = *frame.tracked_slot_perm;
426            }
427            let _ = ManuallyDrop::new(frame);
428            segment.range.end = paddr + PAGE_SIZE;
429            proof {
430                broadcast use group_page_meta;
431
432                segment.tracked_perms.tracked_borrow_mut().tracked_push(
433                    FrameRawPerms { slot_perm, metadata_perm: frame_permission },
434                );
435            }
436
437            i += 1;
438        }
439
440        proof {
441            assert forall|addr: usize|
442                #![trigger frame_to_index(addr)]
443                range.start <= addr < range.end && addr % PAGE_SIZE == 0 implies {
444                regions.contains(frame_to_index(addr))
445            } by {
446                let j = (addr - range.start) / PAGE_SIZE as int;
447                assert(frame_idx_at(range.start, j) == frame_to_index(addr));
448            }
449            assert forall|i: int|
450                #![trigger frame_to_index((segment.range.start + i * PAGE_SIZE) as usize)]
451                0 <= i < segment.len() implies {
452                let idx = frame_to_index((segment.range.start + i * PAGE_SIZE) as usize);
453                &&& segment.tracked_perms@->0[i].inv()
454                &&& segment.tracked_perms@->0[i].slot_perm == regions.slots[idx]
455                &&& segment.tracked_perms@->0[i].metadata_perm.id()
456                    == regions.slot_owners[idx].metadata_perm.id()
457                &&& regions.contains(idx)
458                &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
459                &&& regions.ref_count(idx) > 0
460                &&& regions.ref_count(idx) <= REF_COUNT_MAX
461                &&& regions.slot_owners[idx].paths_in_pt.is_empty()
462                &&& regions.slot_owners[idx].usage
463                    == segment.tracked_perms@->0[i].metadata_perm.resource().usage()
464            } by {
465                assert(frame_idx_at(range.start, i) == frame_to_index(
466                    (segment.range.start + i * PAGE_SIZE) as usize,
467                ));
468            }
469
470        }
471
472        Ok(segment)
473    }
474
475    /// Restores the [`Segment`] from the raw physical address range.
476    ///
477    /// # Verified Properties
478    /// ## Preconditions
479    ///
480    /// ## Postconditions
481    /// - the returned segment satisfies its invariant;
482    /// - the returned segment has the same physical address range as the input;
483    ///
484    /// # Safety
485    ///
486    /// The range must be a forgotten [`Segment`] that matches the type `M`.
487    /// The caller must ensure the range was previously produced by [`Self::into_raw`]
488    /// and that the metadata region still records the segment obligations.
489    #[verus_spec(r =>
490        with
491            Tracked(raw_perms): Tracked<Seq<FrameRawPerms>>,
492        requires
493            range.start % PAGE_SIZE == 0,
494            range.end % PAGE_SIZE == 0,
495            range.start <= range.end <= MAX_PADDR,
496            raw_perms.len() == (range.end - range.start) / PAGE_SIZE as int,
497            forall |i: int| #![trigger raw_perms[i]]
498                0 <= i < raw_perms.len() ==> {
499                    let paddr = (range.start + i * PAGE_SIZE) as usize;
500                    &&& raw_perms[i].slot_vaddr() == frame_to_meta(paddr)
501                    &&& raw_perms[i].inv()
502                },
503        ensures
504            r.inv(),
505            r.range() == range,
506    )]
507    pub(crate) unsafe fn from_raw(range: Range<Paddr>) -> Self {
508        proof_with!{ tracked_perms: Tracked(Some(raw_perms)) }
509        Self { range, _marker: core::marker::PhantomData }
510    }
511}
512
513#[verus_verify]
514impl<M: AnyFrameMeta + ?Sized> Segment<M> {
515    /// Gets the start physical address of the contiguous frames.
516    #[verus_verify(dual_spec)]
517    #[verus_spec(
518        returns
519            self.start_paddr(),
520    )]
521    pub fn start_paddr(&self) -> Paddr {
522        self.range.start
523    }
524
525    /// Gets the end physical address of the contiguous frames.
526    #[verus_verify(dual_spec)]
527    #[verus_spec(
528        returns
529            self.end_paddr(),
530    )]
531    pub fn end_paddr(&self) -> Paddr {
532        self.range.end
533    }
534
535    /// Gets the length in bytes of the contiguous frames.
536    #[verus_verify(dual_spec)]
537    #[verus_spec(r =>
538        requires
539            self.inv(),
540        ensures
541            r == self.end_paddr() - self.start_paddr(),
542        returns
543            self.size()
544    )]
545    pub fn size(&self) -> usize {
546        self.range.end - self.range.start
547    }
548
549    pub open spec fn range(&self) -> Range<Paddr> {
550        self.start_paddr()..self.end_paddr()
551    }
552
553    /// Returns the number of pages of the contiguous frames.
554    pub open spec fn len(&self) -> int {
555        (self.size() / PAGE_SIZE) as int
556    }
557
558    pub closed spec fn raw_perms(&self) -> Seq<FrameRawPerms> {
559        self.tracked_perms@->0
560    }
561
562    pub open spec fn metadata_perms(&self) -> Seq<FracMetadataPerm> {
563        self.raw_perms().map_values(|perm: FrameRawPerms| perm.metadata_perm)
564    }
565
566    pub closed spec fn inner_perm_inv(&self) -> bool {
567        self.tracked_perms@ is Some
568    }
569
570    pub open spec fn slot_perms(&self) -> Seq<&'static PointsTo<MetaSlot>> {
571        self.raw_perms().map_values(|perm: FrameRawPerms| perm.slot_perm)
572    }
573}
574
575#[verus_verify]
576impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Segment<M> {
577    /// Splits the frames into two at the given byte offset from the start.
578    ///
579    /// The resulting frames cannot be empty. So the offset cannot be neither
580    /// zero nor the length of the frames.
581    ///
582    /// # Verified Properties
583    /// ## Preconditions
584    /// - the segment must satisfy its invariant;
585    /// - the offset must be aligned and within bounds;
586    ///
587    /// ## Postconditions
588    /// - the resulting segments satisfy their invariants;
589    /// - they match [`Self::split_spec`].
590    #[verus_spec(r =>
591        requires
592            self.inv(),
593            offset % PAGE_SIZE != 0 ==> may_panic(),
594            !(0 < offset && offset < self.size()) ==> may_panic(),
595        ensures
596            (r.0, r.1) == self.split_spec(offset),
597    )]
598    #[verifier::spinoff_prover]
599    pub fn split(mut self, offset: usize) -> (Self, Self) {
600        assert!(offset % PAGE_SIZE == 0);
601        assert!(0 < offset && offset < self.size());
602
603        let tracked mut left_perms = self.tracked_perms.tracked_take();
604        let tracked right_perms = seq_tracked_split_at(
605            &mut left_perms,
606            (offset / PAGE_SIZE) as int,
607        );
608        let old = ManuallyDrop::new(self);
609        let at = old.range.start + offset;
610
611        (
612            Self {
613                range: old.range.start..at,
614                _marker: core::marker::PhantomData,
615                #[cfg(verus_keep_ghost_body)]
616                tracked_perms: Tracked(Some(left_perms)),
617            },
618            Self {
619                range: at..old.range.end,
620                _marker: core::marker::PhantomData,
621                #[cfg(verus_keep_ghost_body)]
622                tracked_perms: Tracked(Some(right_perms)),
623            },
624        )
625    }
626
627    /// Precise panic condition for [`Self::slice`]. `slice` diverges iff:
628    ///  - the slice range is misaligned, reversed, or out of the segment's
629    ///    bounds (the diverging `assert!`s at the top of `slice`), or
630    ///  - **the specific per-frame slot that `slice` bumps** is already
631    ///    saturated (`inc_ref_count` would overflow). Unlike `query` which
632    ///    clones one item, `slice` bumps one refcount per page in the
633    ///    slice range, so the saturation disjunct is an *exists* over those
634    ///    specific paddrs `self.range.start + j * PAGE_SIZE` for
635    ///    `j ∈ [range.start/PAGE_SIZE, range.end/PAGE_SIZE)`.
636    pub open spec fn page_in_range_saturated(
637        self,
638        range: &Range<usize>,
639        regions: MetaRegionOwners,
640    ) -> bool {
641        exists|j: int|
642            #![trigger frame_to_index((self.start_paddr() + j * PAGE_SIZE) as usize)]
643            (range.start as int) / (PAGE_SIZE as int) <= j < (range.end as int) / (PAGE_SIZE as int)
644                && regions.slot_owner((self.start_paddr() + j * PAGE_SIZE) as usize).ref_count()
645                >= REF_COUNT_MAX
646    }
647
648    // [FIXED] BUG FOUND BY FV: potential overflow. https://github.com/asterinas/asterinas/pull/3587
649    /// Gets an extra handle to the frames in the byte offset range.
650    ///
651    /// The sliced byte offset range in indexed by the offset from the start of
652    /// the contiguous frames. The resulting frames holds extra reference counts.
653    ///
654    /// # Verified Properties
655    /// ## Postconditions
656    /// - the resulting slice's range matches the slicing range and is in-bounds
657    ///   (the in-bounds check follows from the diverging `assert!` in the body);
658    /// - `regions` preserves invariants and key domains. Per-frame state for a
659    ///   hypothetical sub-segment relation is not exposed; threading that through
660    ///   the per-frame ref-count bump loop would require a much heavier proof.
661    ///   Mirrors [`Segment::clone`].
662    ///
663    /// See also [`vstd::seq::Seq::subrange`].
664    #[verus_spec(r =>
665        with
666            Tracked(regions): Tracked<&mut MetaRegionOwners>,
667        requires
668            self.inv(),
669            old(regions).inv(),
670            self.relate_regions(*old(regions)),
671            range.start % PAGE_SIZE != 0 ==> may_panic(),
672            range.end % PAGE_SIZE != 0 ==> may_panic(),
673            range.start > range.end ==> may_panic(),
674            range.end > self.size() ==> may_panic(),
675            self.page_in_range_saturated(range, *old(regions)) ==> may_panic(),
676        ensures
677            range.start % PAGE_SIZE == 0,
678            range.end % PAGE_SIZE == 0,
679            range.start <= range.end,
680            self.start_paddr() + range.end <= self.end_paddr(),
681            !self.page_in_range_saturated(range, *old(regions)),
682            r.inv(),
683            r.start_paddr() == self.start_paddr() + range.start,
684            r.end_paddr() == self.start_paddr() + range.end,
685            r.end_paddr() <= self.end_paddr(),
686            final(regions).inv(),
687            final(regions).slots == old(regions).slots,
688            final(regions).slot_owners.dom() == old(regions).slot_owners.dom(),
689            r.relate_regions(*final(regions)),
690    )]
691    #[verifier::spinoff_prover]
692    pub fn slice(&self, range: &Range<usize>) -> Self {
693        assert!(range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0);
694        assert!(range.start <= range.end && range.end <= self.size());
695        let start = self.range.start + range.start;
696        let end = self.range.start + range.end;
697
698        let mut paddr = start;
699        let ghost addr_len = (end - start) / PAGE_SIZE as int;
700        let ghost first_perm_idx: int = (range.start / PAGE_SIZE) as int;
701        let ghost mut i: int = 0;
702        proof_decl! {
703            let tracked mut raw_perms = Seq::<FrameRawPerms>::tracked_empty();
704        }
705        loop
706            invariant
707                self.inv(),
708                self.relate_regions(*old(regions)),
709                range.start == first_perm_idx * PAGE_SIZE,
710                range.start <= range.end <= self.size(),
711                start == self.range.start + range.start,
712                end == self.range.start + range.end,
713                end == start + addr_len * PAGE_SIZE,
714                self.page_in_range_saturated(range, *old(regions)) ==> may_panic(),
715                regions.inv(),
716                regions.slots == old(regions).slots,
717                regions.slot_owners.dom() == old(regions).slot_owners.dom(),
718                raw_perms.len() == i,
719                forall|j: int|
720                    #![trigger raw_perms[j]]
721                    0 <= j < raw_perms.len() ==> {
722                        let idx = frame_to_index((start + j * PAGE_SIZE) as usize);
723                        &&& raw_perms[j].slot_perm == regions.slots[idx]
724                        &&& raw_perms[j].inv()
725                        &&& raw_perms[j].metadata_perm.id()
726                            == regions.slot_owners[idx].metadata_perm.id()
727                    },
728                forall|j: int|
729                    #![trigger frame_to_index((start + j * PAGE_SIZE) as usize)]
730                    0 <= j < raw_perms.len() ==> {
731                        let idx = frame_to_index((start + j * PAGE_SIZE) as usize);
732                        &&& regions.contains(idx)
733                        &&& regions.slot_owners[idx].slot_vaddr == index_to_meta(idx)
734                        &&& regions.ref_count(idx) > 0
735                        &&& regions.ref_count(idx) <= REF_COUNT_MAX
736                        &&& regions.slot_owners[idx].paths_in_pt.is_empty()
737                        &&& regions.slot_owners[idx].usage
738                            == raw_perms[j].metadata_perm.resource().usage()
739                    },
740                paddr == start + i * PAGE_SIZE,
741                paddr <= end,
742                0 <= i <= addr_len,
743                paddr < end <==> i < addr_len,
744                forall|j: int|
745                    #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
746                    first_perm_idx + i <= j < first_perm_idx + addr_len ==> (*regions).slot_owner(
747                        (self.range.start + j * PAGE_SIZE) as usize,
748                    ) == old(regions).slot_owner((self.range.start + j * PAGE_SIZE) as usize),
749                forall|j: int|
750                    #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
751                    first_perm_idx <= j < first_perm_idx + i ==> old(regions).slot_owner(
752                        (self.range.start + j * PAGE_SIZE) as usize,
753                    ).ref_count() < REF_COUNT_MAX,
754            ensures
755                paddr == end,
756                i == addr_len,
757            decreases addr_len - i,
758        {
759            if paddr >= end {
760                break;
761            }
762            let ghost perm_idx: int = first_perm_idx + i;
763
764            proof {
765                assert(paddr == (self.range.start + perm_idx * PAGE_SIZE) as usize);
766            }
767
768            let tracked_permission = unsafe {
769                #[verus_spec(with Tracked(regions))]
770                crate::mm::frame::inc_frame_ref_count(paddr)
771            };
772            let tracked frame_permission = tracked_permission.get();
773            proof {
774                frame_permission.agree(
775                    &self.tracked_perms.borrow().tracked_borrow().tracked_borrow(
776                        perm_idx,
777                    ).metadata_perm,
778                );
779                let tracked slot_perm = regions.tracked_borrow_slot(paddr);
780                raw_perms.tracked_push(
781                    FrameRawPerms { slot_perm, metadata_perm: frame_permission },
782                );
783            }
784
785            paddr += PAGE_SIZE;
786
787            proof {
788                i = i + 1;
789            }
790        }
791
792        proof_with!{ tracked_perms: Tracked(Some(raw_perms)) }
793        Self { range: start..end, _marker: core::marker::PhantomData }
794    }
795
796    /// Forgets the [`Segment`] and gets a raw range of physical addresses.
797    /// # Verified Properties
798    /// ## Preconditions
799    /// - the segment must satisfy its invariant.
800    ///
801    /// ## Postconditions
802    /// - the returned physical address range matches the segment's range.
803    #[verus_spec(r =>
804        with
805            -> raw_perms: Tracked<Seq<FrameRawPerms>>,
806        requires
807            self.inv(),
808        ensures
809            r == self.range(),
810            raw_perms@ == self.raw_perms(),
811    )]
812    pub(crate) fn into_raw(mut self) -> Range<Paddr> {
813        let range = self.range.clone();
814
815        proof_decl!{
816            let tracked raw_perms = self.tracked_perms.tracked_take();
817        }
818
819        let _ = ManuallyDrop::new(self);
820
821        proof_with!(|= Tracked(raw_perms));
822        range
823    }
824
825    /// Splits the contiguous frames into two at the given byte offset from the start in spec mode.
826    pub closed spec fn split_spec(self, offset: usize) -> (Self, Self)
827        recommends
828            offset % PAGE_SIZE == 0,
829            0 < offset < self.size(),
830    {
831        let at = (self.start_paddr() + offset) as usize;
832        let idx = offset / PAGE_SIZE;
833        (
834            Self {
835                range: self.start_paddr()..at,
836                _marker: core::marker::PhantomData,
837                #[cfg(verus_keep_ghost_body)]
838                tracked_perms: Tracked(Some(self.raw_perms()[..idx])),
839            },
840            Self {
841                range: at..self.end_paddr(),
842                _marker: core::marker::PhantomData,
843                #[cfg(verus_keep_ghost_body)]
844                tracked_perms: Tracked(Some(self.raw_perms()[idx..])),
845            },
846        )
847    }
848}
849
850impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> FromSpecImpl<Frame<M>> for Segment<M> {
851    open spec fn obeys_from_spec() -> bool {
852        true
853    }
854
855    closed spec fn from_spec(frame: Frame<M>) -> Self {
856        let paddr = frame.start_paddr_spec();
857        let slot_perm = frame.slot_perm();
858        let metadata_perm = frame.frac_metadata_perm();
859        let perm =
860            seq!{
861            FrameRawPerms { slot_perm: &slot_perm, metadata_perm}
862        };
863        Self {
864            range: paddr..(paddr + PAGE_SIZE) as usize,
865            _marker: core::marker::PhantomData,
866            #[cfg(verus_keep_ghost_body)]
867            tracked_perms: Tracked(Some(perm)),
868        }
869    }
870}
871
872#[verus_verify]
873impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> From<Frame<M>> for Segment<M> {
874    fn from(frame: Frame<M>) -> Self {
875        assume(frame.inv());
876
877        let mut frame = frame;
878        let pa = frame.start_paddr();
879        proof_decl!{
880            let tracked frame_perm =
881                FrameRawPerms{
882                    slot_perm: *frame.tracked_slot_perm.borrow(),
883                    metadata_perm: frame.tracked_metadata_perm.tracked_take()
884                };
885            let tracked perms = Seq::tracked_empty();
886            perms.tracked_push(frame_perm);
887        }
888        let _ = ManuallyDrop::new(frame);
889        Self {
890            range: pa..(pa + PAGE_SIZE),
891            _marker: core::marker::PhantomData,
892            #[cfg(verus_keep_ghost_body)]
893            tracked_perms: Tracked(Some(perms)),
894        }
895    }
896}
897
898impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Iterator for Segment<M> {
899    type Item = Frame<M>;
900
901    #[verifier::rlimit(200)]
902    fn next(&mut self) -> Option<Self::Item> {
903        proof {
904            // This is a verification limitation that the `#[verifier::type_invariant]` can not be broken.
905            // It is still sound because `Segment` is always exposed with `inv`.
906            assume(self.inv());
907        }
908
909        if self.range.start < self.range.end {
910            proof {
911                assert(self.raw_perms()[0].slot_perm == self.slot_perms()[0]);
912                assert(self.raw_perms()[0].metadata_perm == self.metadata_perms()[0]);
913            }
914            let tracked mut raw_perms = self.tracked_perms.tracked_borrow_mut();
915            let tracked perm = raw_perms.tracked_pop_front();
916            proof {
917                assert(perm.inv());
918                assert(perm.slot_vaddr() == frame_to_meta(self.range.start));
919            }
920            // SAFETY: each frame in the range would be a handle forgotten
921            // when creating the `Segment` object.
922            let frame = unsafe {
923                #[verus_spec(with Tracked(perm))]
924                Frame::<M>::from_raw(self.range.start)
925            };
926            self.range.start += PAGE_SIZE;
927            Some(frame)
928        } else {
929            None
930        }
931    }
932}
933
934impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> IteratorSpecImpl for Segment<M> {
935    open spec fn obeys_prophetic_iter_laws(&self) -> bool {
936        true
937    }
938
939    #[verifier::prophetic]
940    closed spec fn remaining(&self) -> Seq<Self::Item> {
941        Seq::new(
942            self.metadata_perms().len() as nat,
943            |i: int|
944                {
945                    Frame::<M>::from_raw_spec(
946                        (self.range().start + i * PAGE_SIZE) as usize,
947                        self.slot_perms()[i],
948                        Some(self.metadata_perms()[i]),
949                    )
950                },
951        )
952    }
953
954    #[verifier::prophetic]
955    closed spec fn produces(&self) -> Seq<bool> {
956        Seq::new(IteratorSpec::remaining(self).len(), |i: int| true)
957    }
958
959    closed spec fn decrease(&self) -> Option<nat> {
960        Some(self.len() as nat)
961    }
962
963    open spec fn peek(&self, index: int) -> Option<Self::Item> {
964        if 0 <= index < self.metadata_perms().len() {
965            Some(
966                Frame::<M>::from_raw_spec(
967                    (self.range().start + index * PAGE_SIZE) as usize,
968                    self.slot_perms()[index],
969                    Some(self.metadata_perms()[index]),
970                ),
971            )
972        } else {
973            None
974        }
975    }
976}
977
978impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Segment<M> {
979    #[verus_spec(
980        with Tracked(regions): Tracked<&mut MetaRegionOwners>
981        requires
982            old(regions).inv(),
983            self.inv(),
984            self.relate_regions(*old(regions)),
985            forall|i: int|
986                #![trigger frame_to_index((self.start_paddr() + i * PAGE_SIZE) as usize)]
987                0 <= i < self.len() ==> {
988                    let idx = frame_to_index((self.start_paddr() + i * PAGE_SIZE) as usize);
989                    &&& old(regions).slot_owners[idx].storage_perm().is_init()
990                    &&& old(regions).ref_count(idx) == 1 ==> {
991                        &&& old(regions).slot_owners[idx].in_list_perm.value() == 0
992                    }
993                },
994        ensures
995            final(regions).inv(),
996    )]
997    pub fn drop(self) {
998        let ghost n = self.len();
999        let mut paddr = self.range.start;
1000        let tracked mut raw_perms = self.tracked_perms.get().tracked_unwrap();
1001
1002        let ghost mut k: int = 0;
1003
1004        loop
1005            invariant
1006                old(regions).inv(),
1007                regions.inv(),
1008                self.inv(),
1009                raw_perms.len() == n - k,
1010                forall|j: int|
1011                    #![trigger raw_perms[j]]
1012                    0 <= j < raw_perms.len() ==> {
1013                        let idx = frame_to_index((self.range.start + (k + j) * PAGE_SIZE) as usize);
1014                        &&& raw_perms[j].inv()
1015                        &&& raw_perms[j].slot_perm == regions.slots[idx]
1016                        &&& raw_perms[j].metadata_perm.id()
1017                            == regions.slot_owners[idx].metadata_perm.id()
1018                    },
1019                self.range.start <= paddr <= self.range.end,
1020                paddr == (self.range.start + k * PAGE_SIZE) as usize,
1021                paddr % PAGE_SIZE == 0,
1022                paddr <= MAX_PADDR,
1023                0 <= k <= n,
1024                n == (self.range.end - self.range.start) / PAGE_SIZE as int,
1025                paddr < self.range.end <==> k < n,
1026                forall|j: int|
1027                    #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1028                    k <= j < n ==> {
1029                        let idx = frame_to_index((self.range.start + j * PAGE_SIZE) as usize);
1030                        &&& regions.contains(idx)
1031                        &&& regions.slot_owners[idx] == old(regions).slot_owners[idx]
1032                    },
1033                forall|j: int|
1034                    #![trigger frame_idx_at(self.range.start, j)]
1035                    k <= j < n ==> regions.contains(frame_idx_at(self.range.start, j))
1036                        && regions.slot_owners[frame_idx_at(self.range.start, j)] == old(
1037                        regions,
1038                    ).slot_owners[frame_idx_at(self.range.start, j)],
1039                regions.slot_owners.dom() == old(regions).slot_owners.dom(),
1040                self.relate_regions(*old(regions)),
1041                forall|i: int|
1042                    #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1043                    0 <= i < n ==> {
1044                        let idx = frame_to_index((self.range.start + i * PAGE_SIZE) as usize);
1045                        &&& old(regions).slot_owners[idx].storage_perm().is_init()
1046                        &&& old(regions).ref_count(idx) == 1 ==> {
1047                            &&& old(regions).slot_owners[idx].in_list_perm.value() == 0
1048                        }
1049                    },
1050            decreases n - k,
1051        {
1052            if paddr >= self.range.end {
1053                break;
1054            }
1055            proof {
1056                assert(valid_frame_paddr(paddr));
1057                lemma_paddr_to_meta_biinjective(paddr);
1058                lemma_frame_to_meta_soundness(paddr);
1059            }
1060            let tracked perm = raw_perms.tracked_pop_front();
1061            let frame = unsafe {
1062                #[verus_spec(with Tracked(perm))]
1063                Frame::<M>::from_raw(paddr)
1064            };
1065
1066            frame.drop(Tracked(regions));
1067
1068            paddr += PAGE_SIZE;
1069
1070            proof {
1071                k = k + 1;
1072            }
1073        }
1074    }
1075}
1076
1077/*impl<M: AnyFrameMeta> TryFrom<Segment<dyn AnyFrameMeta>> for Segment<M> {
1078    type Error = Segment<dyn AnyFrameMeta>;
1079
1080    open spec fn clone_ensures(
1081        self,
1082        old_perm: MetaRegionOwners,
1083        new_perm: MetaRegionOwners,
1084        res: Self,
1085    ) -> bool {
1086        &&& res.range == self.range
1087        &&& res.inv()
1088        &&& new_perm.inv()
1089    }
1090
1091    fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self) {
1092        let mut paddr = self.range.start;
1093
1094        let ghost old_perm = *perm;
1095        loop
1096            invariant
1097                perm.inv(),
1098                self.inv(),
1099                perm.slots == old_perm.slots,
1100                perm.slot_owners.dom() == old_perm.slot_owners.dom(),
1101                // Linear-drop pilot: cloning a Segment doesn't mint or
1102                // redeem its obligation — the per-frame ref-count bump is
1103                // an Arc-style operation.
1104                self.range.start <= paddr <= self.range.end,
1105                paddr % PAGE_SIZE == 0,
1106                paddr <= MAX_PADDR,
1107                forall|pa: Paddr|
1108                    #![trigger frame_to_index(pa)]
1109                    (paddr <= pa < self.range.end && pa % PAGE_SIZE == 0) ==> {
1110                        let idx = frame_to_index(pa);
1111                        &&& perm.contains(idx)
1112                        &&& valid_frame_paddr(pa)
1113                        &&& perm.ref_count(idx) > 0
1114                        &&& perm.ref_count(idx) + 1
1115                            < REF_COUNT_MAX
1116                        &&& !MetaSlot::inc_ref_count_panic_cond(
1117                            perm.slot_owners[idx].ref_count_perm,
1118                        )
1119                    },
1120            decreases self.range.end - paddr,
1121        {
1122            if paddr >= self.range.end {
1123                break;
1124            }
1125            #[verus_spec(with Tracked(perm))]
1126            crate::mm::frame::inc_frame_ref_count(paddr);
1127
1128            paddr = paddr + PAGE_SIZE;
1129        }
1130        // Since segments are homogeneous, we can safely assume that the rest
1131        // of the frames are of the same type. We just debug-check here.
1132        #[cfg(debug_assertions)]
1133        {
1134            for paddr in seg.range.clone().step_by(PAGE_SIZE) {
1135                let frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(paddr) };
1136                let frame = ManuallyDrop::new(frame);
1137                debug_assert!((frame.dyn_meta() as &dyn core::any::Any).is::<M>());
1138            }
1139        }
1140        // SAFETY: The metadata is coerceable and the struct is transmutable.
1141        Ok(unsafe { core::mem::transmute::<Segment<dyn AnyFrameMeta>, Segment<M>>(seg) })
1142    }
1143}
1144
1145impl<M: AnyUFrameMeta> From<Segment<M>> for USegment {
1146    fn from(seg: Segment<M>) -> Self {
1147        // SAFETY: The metadata is coerceable and the struct is transmutable.
1148        unsafe { core::mem::transmute(seg) }
1149    }
1150}
1151
1152impl TryFrom<Segment<dyn AnyFrameMeta>> for USegment {
1153    type Error = Segment<dyn AnyFrameMeta>;
1154
1155    /// Try converting a [`Segment<dyn AnyFrameMeta>`] into [`USegment`].
1156    ///
1157    /// If the usage of the page is not the same as the expected usage, it will
1158    /// return the dynamic page itself as is.
1159    fn try_from(seg: Segment<dyn AnyFrameMeta>) -> core::result::Result<Self, Self::Error> {
1160        // SAFETY: for each page there would be a forgotten handle
1161        // when creating the `Segment` object.
1162        let first_frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(seg.range.start) };
1163        let first_frame = ManuallyDrop::new(first_frame);
1164        if !first_frame.dyn_meta().is_untyped() {
1165            return Err(seg);
1166        }
1167        // Since segments are homogeneous, we can safely assume that the rest
1168        // of the frames are of the same type. We just debug-check here.
1169        #[cfg(debug_assertions)]
1170        {
1171            for paddr in seg.range.clone().step_by(PAGE_SIZE) {
1172                let frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(paddr) };
1173                let frame = ManuallyDrop::new(frame);
1174                debug_assert!(frame.dyn_meta().is_untyped());
1175            }
1176        }
1177        // SAFETY: The metadata is coerceable and the struct is transmutable.
1178        Ok(unsafe { core::mem::transmute::<Segment<dyn AnyFrameMeta>, USegment>(seg) })
1179    }
1180} */
1181
1182impl<M: AnyFrameMeta + ?Sized> Inv for Segment<M> {
1183    /// The invariant of a [`Segment`]:
1184    ///
1185    /// - the physical addresses of the frames are aligned and within bounds.
1186    /// - the range is well-formed, i.e., the start is less than or equal to the end.
1187    open spec fn inv(self) -> bool {
1188        &&& self.start_paddr() % PAGE_SIZE == 0
1189        &&& self.end_paddr() % PAGE_SIZE == 0
1190        &&& self.start_paddr() <= self.end_paddr() <= MAX_PADDR
1191        &&& self.inner_perm_inv()
1192        &&& self.raw_perms().len() == self.len()
1193        &&& forall|i: int|
1194            #![trigger self.raw_perms()[i]]
1195            0 <= i < self.raw_perms().len() ==> {
1196                let paddr = (self.range().start + i * PAGE_SIZE) as usize;
1197                &&& self.raw_perms()[i].slot_vaddr() == frame_to_meta(paddr)
1198                &&& self.raw_perms()[i].inv()
1199            }
1200    }
1201}
1202
1203} // verus!