Skip to main content

PageTablePageMeta

Struct PageTablePageMeta 

Source
pub struct PageTablePageMeta<C: PageTableConfig> {
    pub nr_children: PCell<u16>,
    pub stray: PCell<bool>,
    pub level: PagingLevel,
    pub lock: PAtomicU8,
    pub _phantom: PhantomData<C>,
}
Expand description

The metadata of any kinds of page table pages. Make sure the the generic parameters don’t effect the memory layout.

Fields§

§nr_children: PCell<u16>

The number of valid PTEs. It is mutable if the lock is held.

§stray: PCell<bool>

If the page table is detached from its parent.

A page table can be detached from its parent while still being accessed, since we use a RCU scheme to recycle page tables. If this flag is set, it means that the parent is recycling the page table.

§level: PagingLevel

The level of the page table page. A page table page cannot be referenced by page tables of different levels.

§lock: PAtomicU8

The lock for the page table page.

§_phantom: PhantomData<C>

Implementations§

Source§

impl<C: PageTableConfig> PageTablePageMeta<C>

Source

pub exec fn new(level: PagingLevel) -> Self

Source

pub open spec fn walk_pte_at_view(view: MemView, c: usize) -> C::E

{ ostd_pod::decode_pod::<C::E>(view.read_bytes(c, core::mem::size_of::<C::E>())) }

The PTE value that read_once::<C::E> would produce at cursor c against the given memory view. Linked to read_once via pod_bytes(v) == read_view.read_bytes(...) (strengthened ensures) and the checked byte-decoding model.

Source

pub open spec fn walk_coverage_at(self, view: MemView, dom: Set<int>, c: usize) -> bool

{
    let pte = Self::walk_pte_at_view(view, c);
    pte.is_present() && !pte.is_last(self.level)
        ==> dom.contains(frame_to_index(pte.paddr()))
}

Single-cursor projection of [walk_coverage_from_view]. Extracting the forall body to a named predicate lets the body invoke [lemma_coverage_at] for one specific c instead of relying on auto-trigger matching across the loop invariant’s forall|c|.

Source

pub proof fn lemma_coverage_at( self, reader: VmReader<'_, Infallible>, view: MemView, dom: Set<int>, c: usize, )

requires
self.walk_coverage_from_view(reader, view, dom),
reader.cursor.vaddr <= c,
c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
(c - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
ensures
self.walk_coverage_at(view, dom, c),

Instantiate [walk_coverage_from_view]’s forall at one cursor.

Source

pub proof fn lemma_uniqueness_at_pair( self, reader: VmReader<'_, Infallible>, view: MemView, c1: usize, c2: usize, )

requires
self.walk_uniqueness_from_view(reader, view),
reader.cursor.vaddr <= c1,
c1 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
(c1 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
reader.cursor.vaddr <= c2,
c2 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
(c2 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
c1 != c2,
Self::walk_pte_at_view(view, c1).is_present(),
!Self::walk_pte_at_view(view, c1).is_last(self.level),
Self::walk_pte_at_view(view, c2).is_present(),
!Self::walk_pte_at_view(view, c2).is_last(self.level),
ensures
Self::walk_pte_at_view(view, c1).paddr() != Self::walk_pte_at_view(view, c2).paddr(),

Instantiate [walk_uniqueness_from_view]’s forall at one cursor pair.

Source

pub open spec fn walk_coverage_from_view( self, reader: VmReader<'_, Infallible>, view: MemView, dom: Set<int>, ) -> bool

{
    forall |c: usize| {
        reader.cursor.vaddr <= c
            && c + core::mem::size_of::<C::E>()
                <= reader.cursor.vaddr + reader.remain_spec()
            && (c - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0
            ==> {
                let pte = Self::walk_pte_at_view(view, c);
                pte.is_present() && !pte.is_last(self.level)
                    ==> dom.contains(frame_to_index(pte.paddr()))
            }
    }
}

Caller-side dom-membership obligation: every present non-last PTE position in the walk (over view) has its child-frame index in dom. Phrased over a frozen (view, dom) pair so the body can carry it as a loop invariant against an entry-state snapshot while vm_io_owner advances per iteration.

Source

pub open spec fn walk_uniqueness_from_view( self, reader: VmReader<'_, Infallible>, view: MemView, ) -> bool

{
    forall |c1: usize, c2: usize| {
        reader.cursor.vaddr <= c1
            && c1 + core::mem::size_of::<C::E>()
                <= reader.cursor.vaddr + reader.remain_spec()
            && (c1 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0
            && reader.cursor.vaddr <= c2
            && c2 + core::mem::size_of::<C::E>()
                <= reader.cursor.vaddr + reader.remain_spec()
            && (c2 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0
            && c1 != c2
            ==> {
                let pte1 = Self::walk_pte_at_view(view, c1);
                let pte2 = Self::walk_pte_at_view(view, c2);
                pte1.is_present() && !pte1.is_last(self.level) && pte2.is_present()
                    && !pte2.is_last(self.level) ==> pte1.paddr() != pte2.paddr()
            }
    }
}

Caller-side uniqueness obligation: distinct cursor positions with present non-last PTEs (in view) map to distinct paddrs.

Source

pub open spec fn child_perms_embedding( regions: MetaRegionOwners, excluded: Set<int>, ) -> bool

{
    forall |paddr: crate::mm::Paddr| {
        regions.slots.dom().contains(frame_to_index(paddr))
            && !excluded.contains(frame_to_index(paddr))
            ==> {
                let idx = frame_to_index(paddr);
                let so = regions.slot_owners[idx];
                &&& <Frame<Self>>::from_raw_requires(regions, paddr)
                &&& 0 < so.ref_count() <= REF_COUNT_MAX
                &&& so.storage_perm().is_init()
                &&& so.ref_count() == 1
                    ==> {
                        &&& so.in_list_perm.value() == 0
                        &&& so.paths_in_pt.is_empty()

                    }

            }
    }
}

Caller-side shape obligation: every paddr in child_perms.dom() has a slot perm matching the shape from_raw + VerifiedDrop::drop expect (init, alignment, refcount within bounds, last-reference shape when refcount == 1).

Source§

impl<C: PageTableConfig> PageTablePageMeta<C>

Source

pub open spec fn into_spec(self) -> StoredPageTablePageMeta

{
    StoredPageTablePageMeta {
        nr_children: self.nr_children,
        stray: self.stray,
        level: self.level,
        lock: self.lock,
    }
}
Source

pub exec fn into(self) -> res : StoredPageTablePageMeta

ensures
res == self.into_spec(),

Trait Implementations§

Source§

impl<C: PageTableConfig> AnyFrameMeta for PageTablePageMeta<C>

Source§

open spec fn on_drop_pre( &self, reader: VmReader<'_, Infallible>, regions: MetaRegionOwners, vm_io_owner: VmIoOwner, ) -> bool

{
    &&& reader.inv()
    &&& reader.wf(vm_io_owner)
    &&& reader.remain_spec() >= crate::specs::arch::PAGE_SIZE
    &&& reader.cursor.vaddr % core::mem::align_of::<C::E>() == 0
    &&& vm_io_owner.inv()
    &&& vm_io_owner.read_view_initialized()
    &&& regions.inv()
    &&& Self::child_perms_embedding(regions, vstd::set::Set::empty())
    &&& self
        .walk_coverage_from_view(reader, vm_io_owner.read_view_of(), regions.slots.dom())
    &&& self.walk_uniqueness_from_view(reader, vm_io_owner.read_view_of())

}

Caller invariants the PT-node on_drop body relies on:

  • Reader well-formedness + vm_io_owner matching + read view initialized + at least PAGE_SIZE bytes remaining for the PT-node walk.
  • Global region table invariant.
  • Embedding ([child_perms_embedding]): for every paddr in child_perms.dom(), the slot and perm match from_raw / VerifiedDrop::drop’s expected shape.
  • Walk coverage ([walk_coverage_from_view]): for every present non-last PTE in the page bytes, frame_to_index(pte.paddr()) ∈ child_perms.dom().
  • Walk uniqueness ([walk_uniqueness_from_view]): distinct PTE positions with present non-last PTEs have distinct paddrs.

Coverage and uniqueness retain the memory-safety premises needed by the trusted destructor body, without storing item permissions in VmIoOwner.

Source§

exec fn on_drop( &mut self, reader: &mut VmReader<'_, Infallible>, Tracked(regions): Tracked<&mut MetaRegionOwners>, Tracked(_vm_io_owner): Tracked<&mut VmIoOwner>, )

Drops the children of a page-table node.

The permission handoff for recursively destroying page-table entries is not modeled yet. Keep that trusted boundary local to this destructor; VmIoOwner only supplies the memory view used by reader.

Source§

exec fn is_untyped(&self) -> bool

Source§

uninterp spec fn vtable_ptr(&self) -> usize

Source§

impl<C: PageTableConfig> OwnerOf for PageTablePageMeta<C>

Source§

open spec fn wf(self, owner: Self::Owner) -> bool

{
    &&& self.nr_children.id() == owner.nr_children.id()
    &&& self.stray.id() == owner.stray.id()
    &&& 0 <= owner.nr_children.value() <= NR_ENTRIES

}
Source§

type Owner = PageMetaOwner

The owner of the concrete type. The Owner must implement Inv, indicating that it must has a consistent state.
Source§

impl<C: PageTableConfig> Repr<MetaSlotStorage> for PageTablePageMeta<C>

Source§

open spec fn wf(r: MetaSlotStorage, perm: ()) -> bool

{ matches!(r, MetaSlotStorage::PTNode(_)) }
Source§

open spec fn to_repr_spec(self, perm: ()) -> (MetaSlotStorage, ())

{ (MetaSlotStorage::PTNode(self.into_spec()), ()) }
Source§

exec fn to_repr(self, Tracked(perm): Tracked<&mut ()>) -> MetaSlotStorage

Source§

open spec fn from_repr_spec(r: MetaSlotStorage, perm: ()) -> Self

{
    match r {
        MetaSlotStorage::PTNode(node) => node.into_spec::<C>(),
        _ => arbitrary(),
    }
}
Source§

exec fn from_repr(r: MetaSlotStorage, Tracked(perm): Tracked<&()>) -> Self

Source§

exec fn from_borrowed<'a>( r: &'a MetaSlotStorage, Tracked(perm): Tracked<&'a ()>, ) -> &'a Self

Source§

exec fn from_borrowed_mut<'a>( r: &'a mut MetaSlotStorage, Tracked(perm): Tracked<&'a mut ()>, ) -> &'a mut Self

Source§

proof fn from_to_repr(self, perm: ())

Source§

proof fn to_from_repr(r: MetaSlotStorage, perm: ())

Source§

proof fn to_repr_wf(self, perm: ())

Source§

type ReprPerm = ()

If the underlying representation contains cells, the translation may require permission objects that access them.

Auto Trait Implementations§

§

impl<C> !Freeze for PageTablePageMeta<C>

§

impl<C> !RefUnwindSafe for PageTablePageMeta<C>

§

impl<C> Send for PageTablePageMeta<C>

§

impl<C> Sync for PageTablePageMeta<C>

§

impl<C> Unpin for PageTablePageMeta<C>
where C: Unpin,

§

impl<C> UnsafeUnpin for PageTablePageMeta<C>

§

impl<C> UnwindSafe for PageTablePageMeta<C>
where C: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Conv for T

§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
§

impl<T> FmtForward for T

§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, VERUS_SPEC__A> FromSpec<T> for VERUS_SPEC__A
where VERUS_SPEC__A: From<T>,

§

fn obeys_from_spec() -> bool

§

fn from_spec(v: T) -> VERUS_SPEC__A

§

impl<T> FromSpecImpl<T> for T

§

fn obeys_from_spec() -> bool

§

fn from_spec(v: T) -> T

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T, VERUS_SPEC__A> IntoSpec<T> for VERUS_SPEC__A
where VERUS_SPEC__A: Into<T>,

§

fn obeys_into_spec() -> bool

§

fn into_spec(self) -> T

§

impl<T, U> IntoSpecImpl<U> for T
where U: From<T>,

§

fn obeys_into_spec() -> bool

§

fn into_spec(self) -> U

§

impl<T> Pipe for T
where T: ?Sized,

§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
§

impl<A> SpecEq<&A> for A
where A: ?Sized,

§

impl<A> SpecEq<&mut A> for A
where A: ?Sized,

§

impl<A> SpecEq<A> for A
where A: ?Sized,

§

impl<A> SpecEq<Ghost<A>> for A

§

impl<A> SpecEq<Tracked<A>> for A

§

impl<T> Tap for T

§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
§

impl<T> TryConv for T

§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, VERUS_SPEC__A> TryFromSpec<T> for VERUS_SPEC__A
where VERUS_SPEC__A: TryFrom<T>,

§

fn obeys_try_from_spec() -> bool

§

fn try_from_spec( v: T, ) -> Result<VERUS_SPEC__A, <VERUS_SPEC__A as TryFrom<T>>::Error>

Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T, VERUS_SPEC__A> TryIntoSpec<T> for VERUS_SPEC__A
where VERUS_SPEC__A: TryInto<T>,

§

fn obeys_try_into_spec() -> bool

§

fn try_into_spec(self) -> Result<T, <VERUS_SPEC__A as TryInto<T>>::Error>

§

impl<T, U> TryIntoSpecImpl<U> for T
where U: TryFrom<T>,

§

fn obeys_try_into_spec() -> bool

§

fn try_into_spec(self) -> Result<U, <U as TryFrom<T>>::Error>