#[repr(transparent)]pub struct Segment<M: AnyFrameMeta + ?Sized> {
pub range: Range<Paddr>,
pub _marker: PhantomData<M>,
}Expand description
A contiguous range of homogeneous physical memory frames.
This is a handle to multiple contiguous frames. It will be more lightweight than owning an array of frame handles.
The ownership is achieved by the reference counting mechanism of frames.
When constructing a Segment, the frame handles are created then
forgotten, leaving the reference count. When dropping a it, the frame
handles are restored and dropped, decrementing the reference count.
All the metadata of the frames are homogeneous, i.e., they are of the same type.
Fields§
§range: Range<Paddr>The physical address range of the segment.
_marker: PhantomData<M>Marker for the metadata type.
Implementations§
Source§impl<M: AnyFrameMeta + ?Sized> Segment<M>
impl<M: AnyFrameMeta + ?Sized> Segment<M>
Sourcepub open spec fn inv_with(&self, owner: &SegmentOwner<M>) -> bool
pub open spec fn inv_with(&self, owner: &SegmentOwner<M>) -> bool
{
&&& self.inv()
&&& owner.perms.len() * PAGE_SIZE() == self.range.end - self.range.start
&&& forall |i: int| {
0 <= i < owner.perms.len() as int
==> owner.perms[i].addr()
== meta_addr(
frame_to_index((self.range.start + i * PAGE_SIZE()) as usize),
)
}
}Source§impl<M: AnyFrameMeta> Segment<M>
impl<M: AnyFrameMeta> Segment<M>
Sourcepub open spec fn start_paddr_spec(&self) -> Paddr
pub open spec fn start_paddr_spec(&self) -> Paddr
self.inv(),{ self.range.start }Sourcepub open spec fn end_paddr_spec(&self) -> Paddr
pub open spec fn end_paddr_spec(&self) -> Paddr
self.inv(),{ self.range.end }Sourcepub open spec fn size_spec(&self) -> usize
pub open spec fn size_spec(&self) -> usize
self.inv(),{ (self.range.end - self.range.start) as usize }Sourcepub open spec fn nrpage_spec(&self) -> usize
pub open spec fn nrpage_spec(&self) -> usize
self.inv(),{ self.size_spec() / PAGE_SIZE() }Sourcepub open spec fn split_spec(self, offset: usize) -> (Self, Self)
pub open spec fn split_spec(self, offset: usize) -> (Self, Self)
self.inv(),offset % PAGE_SIZE() == 0,0 < offset < self.size_spec(),{
let at = (self.range.start + offset) as usize;
let idx = at / PAGE_SIZE();
(
Self {
range: self.range.start..at,
_marker: core::marker::PhantomData,
},
Self {
range: at..self.range.end,
_marker: core::marker::PhantomData,
},
)
}Sourcepub exec fn start_paddr(&self) -> res : Paddr
pub exec fn start_paddr(&self) -> res : Paddr
self.inv(),Gets the start physical address of the contiguous frames.
Sourcepub exec fn end_paddr(&self) -> res : Paddr
pub exec fn end_paddr(&self) -> res : Paddr
self.inv(),Gets the end physical address of the contiguous frames.
Sourcepub exec fn size(&self) -> res : usize
pub exec fn size(&self) -> res : usize
self.inv(),Gets the length in bytes of the contiguous frames.
Sourcepub open spec fn from_unused_requires(
regions: MetaRegionOwners,
range: Range<Paddr>,
metadata_fn: impl Fn(Paddr) -> (Paddr, M),
) -> bool
pub open spec fn from_unused_requires( regions: MetaRegionOwners, range: Range<Paddr>, metadata_fn: impl Fn(Paddr) -> (Paddr, M), ) -> bool
{
&&& regions.inv()
&&& range.start % PAGE_SIZE() == 0
&&& range.end % PAGE_SIZE() == 0
&&& range.start <= range.end < MAX_PADDR()
&&& forall |paddr_in: Paddr| {
(range.start <= paddr_in < range.end && paddr_in % PAGE_SIZE() == 0)
==> {
&&& metadata_fn.requires((paddr_in,))
}
}
&&& forall |paddr_in: Paddr, paddr_out: Paddr, m: M| {
metadata_fn.ensures((paddr_in,), (paddr_out, m))
==> {
&&& paddr_out < MAX_PADDR()
&&& paddr_out % PAGE_SIZE() == 0
&&& paddr_in == paddr_out
&&& regions.slots.contains_key(frame_to_index(paddr_out))
&&& !regions.dropped_slots.contains_key(frame_to_index(paddr_out))
&&& regions.slot_owners[frame_to_index(paddr_out)].usage is Unused
&&& regions.slot_owners[frame_to_index(paddr_out)].in_list.points_to(0)
}
}
}Sourcepub open spec fn from_unused_ensures(
old_regions: MetaRegionOwners,
new_regions: MetaRegionOwners,
owner: Option<SegmentOwner<M>>,
range: Range<Paddr>,
metadata_fn: impl Fn(Paddr) -> (Paddr, M),
r: Result<Self, GetFrameError>,
) -> bool
pub open spec fn from_unused_ensures( old_regions: MetaRegionOwners, new_regions: MetaRegionOwners, owner: Option<SegmentOwner<M>>, range: Range<Paddr>, metadata_fn: impl Fn(Paddr) -> (Paddr, M), r: Result<Self, GetFrameError>, ) -> bool
{
&&& r matches Ok(
r,
) ==> {
&&& new_regions.inv()
&&& r.range.start == range.start
&&& r.range.end == range.end
&&& owner matches Some(
owner,
) && {
&&& r.inv_with(&owner)
&&& forall |i: int| {
0 <= i < owner.perms.len() as int
==> {
&&& owner.perms[i].addr()
== meta_addr(
frame_to_index_spec(
(range.start + i * PAGE_SIZE()) as usize,
),
)
}
}
&&& new_regions.paddr_range_not_in_region(range)
}
}
}Sourcepub open spec fn split_requires(self, owner: SegmentOwner<M>, offset: usize) -> bool
pub open spec fn split_requires(self, owner: SegmentOwner<M>, offset: usize) -> bool
{
&&& self.inv_with(&owner)
&&& offset % PAGE_SIZE() == 0
&&& 0 < offset < self.size()
}Sourcepub open spec fn split_ensures(
self,
offset: usize,
lhs: Self,
rhs: Self,
ori_owner: SegmentOwner<M>,
lhs_owner: SegmentOwner<M>,
rhs_owner: SegmentOwner<M>,
) -> bool
pub open spec fn split_ensures( self, offset: usize, lhs: Self, rhs: Self, ori_owner: SegmentOwner<M>, lhs_owner: SegmentOwner<M>, rhs_owner: SegmentOwner<M>, ) -> bool
{
&&& lhs.inv_with(&lhs_owner)
&&& rhs.inv_with(&rhs_owner)
&&& (lhs, rhs) == self.split_spec(offset)
&&& ori_owner.perms =~= (lhs_owner.perms + rhs_owner.perms)
}Sourcepub open spec fn into_raw_requires(
self,
regions: MetaRegionOwners,
owner: SegmentOwner<M>,
) -> bool
pub open spec fn into_raw_requires( self, regions: MetaRegionOwners, owner: SegmentOwner<M>, ) -> bool
{
&&& self.inv_with(&owner)
&&& regions.inv()
&&& owner.inv()
&&& owner.is_disjoint_with_meta_region(®ions)
}Sourcepub open spec fn into_raw_ensures(
self,
regions: MetaRegionOwners,
owner: SegmentOwner<M>,
r: Range<Paddr>,
) -> bool
pub open spec fn into_raw_ensures( self, regions: MetaRegionOwners, owner: SegmentOwner<M>, r: Range<Paddr>, ) -> bool
{
&&& r == self.range
&&& regions.inv()
&&& regions.paddr_range_in_dropped_region(self.range)
}Sourcepub open spec fn from_raw_requires(regions: MetaRegionOwners, range: Range<Paddr>) -> bool
pub open spec fn from_raw_requires(regions: MetaRegionOwners, range: Range<Paddr>) -> bool
{
&&& regions.inv()
&&& regions.paddr_range_in_dropped_region(range)
&&& range.start % PAGE_SIZE() == 0
&&& range.end % PAGE_SIZE() == 0
&&& range.start < range.end < MAX_PADDR()
}Sourcepub open spec fn from_raw_ensures(
self,
old_regions: MetaRegionOwners,
new_regions: MetaRegionOwners,
owner: SegmentOwner<M>,
range: Range<Paddr>,
) -> bool
pub open spec fn from_raw_ensures( self, old_regions: MetaRegionOwners, new_regions: MetaRegionOwners, owner: SegmentOwner<M>, range: Range<Paddr>, ) -> bool
{
&&& self.inv_with(&owner)
&&& self.range == range
&&& new_regions.inv()
&&& new_regions.paddr_range_not_in_region(range)
}Sourcepub open spec fn slice_requires(self, owner: SegmentOwner<M>, range: Range<Paddr>) -> bool
pub open spec fn slice_requires(self, owner: SegmentOwner<M>, range: Range<Paddr>) -> bool
{
&&& self.inv_with(&owner)
&&& range.start % PAGE_SIZE() == 0
&&& range.end % PAGE_SIZE() == 0
&&& self.range.start + range.start <= self.range.start + range.end <= self.range.end
}Sourcepub open spec fn slice_ensures(
self,
owner: SegmentOwner<M>,
range: Range<Paddr>,
res: Self,
) -> bool
pub open spec fn slice_ensures( self, owner: SegmentOwner<M>, range: Range<Paddr>, res: Self, ) -> bool
{
&&& res
.inv_with(
&SegmentOwner {
perms: owner
.perms
.subrange(
(range.start / PAGE_SIZE()) as int,
(range.end / PAGE_SIZE()) as int,
),
},
)
}Sourcepub open spec fn next_requires(self, regions: MetaRegionOwners) -> bool
pub open spec fn next_requires(self, regions: MetaRegionOwners) -> bool
{
&&& self.inv()
&&& regions.inv()
&&& regions.dropped_slots.contains_key(frame_to_index(self.range.start))
&&& !regions.slots.contains_key(frame_to_index(self.range.start))
}Sourcepub open spec fn next_ensures(
old_self: Self,
new_self: Self,
old_regions: MetaRegionOwners,
new_regions: MetaRegionOwners,
res: Option<Frame<M>>,
) -> bool
pub open spec fn next_ensures( old_self: Self, new_self: Self, old_regions: MetaRegionOwners, new_regions: MetaRegionOwners, res: Option<Frame<M>>, ) -> bool
{
&&& new_regions.inv()
&&& new_self.inv()
&&& match res {
None => (
&&& new_self.range.start == old_self.range.end
),
Some(f) => (
&&& new_self.range.start == old_self.range.start + PAGE_SIZE()
&&& f.paddr() == old_self.range.start
&&& forall |i: usize| {
&&& i != frame_to_index(f.paddr())
==> old_regions.dropped_slots[i] == new_regions.dropped_slots[i]
&&& i == frame_to_index(f.paddr())
==> !new_regions.dropped_slots.contains_key(i)
}
),
}
}Sourcepub exec fn from_unused(
range: Range<Paddr>,
metadata_fn: impl Fn(Paddr) -> (Paddr, M),
) -> res : Result<Self, GetFrameError>
pub exec fn from_unused( range: Range<Paddr>, metadata_fn: impl Fn(Paddr) -> (Paddr, M), ) -> res : Result<Self, GetFrameError>
Tracked(regions): Tracked <& mut MetaRegionOwners>,
->
owner: Tracked <Option <SegmentOwner <M>>>,requiresSelf::from_unused_requires(*old(regions), range, metadata_fn),ensuresSelf::from_unused_ensures(*old(regions), *regions, owner@, range, metadata_fn, r),Creates a new Segment from unused frames.
The caller must provide a closure to initialize metadata for all the frames.
The closure receives the physical address of the frame and returns the
metadata, which is similar to core::array::from_fn.
It returns an error if:
- any of the frames cannot be created with a specific reason.
Sourcepub exec fn split(self, offset: usize) -> r : (Self, Self)
pub exec fn split(self, offset: usize) -> r : (Self, Self)
Tracked(owner): Tracked <SegmentOwner <M>>,
Tracked(regions): Tracked <& mut MetaRegionOwners>,
->
frame_perms: (Tracked <SegmentOwner <M>>,Tracked <SegmentOwner <M>>),requiresSelf::split_requires(self, owner, offset),ensuresSelf::split_ensures(self, offset, r.0, r.1, owner, frame_perms.0@, frame_perms.1@),Splits the frames into two at the given byte offset from the start.
The resulting frames cannot be empty. So the offset cannot be neither zero nor the length of the frames.
§Panics
The function panics if the offset is out of bounds, at either ends, or not base-page-aligned.
Sourcepub exec fn slice(&self, range: &Range<Paddr>) -> r : Self
pub exec fn slice(&self, range: &Range<Paddr>) -> r : Self
Tracked(owner): Tracked <& SegmentOwner <M>>,requiresSelf::slice_requires(*self, *owner, *range),ensuresSelf::slice_ensures(*self, *owner, *range, r),Gets an extra handle to the frames in the byte offset range.
The sliced byte offset range in indexed by the offset from the start of the contiguous frames. The resulting frames holds extra reference counts.
§Panics
The function panics if the byte offset range is out of bounds, or if any of the ends of the byte offset range is not base-page aligned.
Sourcepub exec fn next(&mut self) -> res : Option<Frame<M>>
pub exec fn next(&mut self) -> res : Option<Frame<M>>
Tracked(regions): Tracked <& mut MetaRegionOwners>,
Tracked(owner): Tracked <& mut SegmentOwner <M>>,requiresSelf::next_requires(*old(self), *old(regions)),old(owner).perms.len() > 0,ensuresSelf::next_ensures(*old(self), *self, *old(regions), *regions, res),Gets the next frame in the segment (raw), if any.
Since the segments here must be “non-active” where
there is no extra Verus-tracked permission SegmentOwner
associated with it; Segment becomes a kind of “zombie”
container through which we can only iterate the frames and
get the frame out of the regions instead.
Trait Implementations§
Source§impl<M: AnyFrameMeta + ?Sized> Inv for Segment<M>
impl<M: AnyFrameMeta + ?Sized> Inv for Segment<M>
Source§impl<M: AnyFrameMeta + ?Sized> Undroppable for Segment<M>
impl<M: AnyFrameMeta + ?Sized> Undroppable for Segment<M>
Source§open spec fn constructor_requires(self, s: Self::State) -> bool
open spec fn constructor_requires(self, s: Self::State) -> bool
{ true }Source§open spec fn constructor_ensures(self, s0: Self::State, s1: Self::State) -> bool
open spec fn constructor_ensures(self, s0: Self::State, s1: Self::State) -> bool
{ s0 =~= s1 }