pub struct Entry<'a, 'rcu, C: PageTableConfig> {
pub pte: C::E,
pub idx: usize,
pub node: &'a mut PageTableGuard<'rcu, C>,
}Fields§
§pte: C::EThe page table entry.
We store the page table entry here to optimize the number of reads from
the node. We cannot hold a &mut E reference to the entry because that
other CPUs may modify the memory location for accessed/dirty bits. Such
accesses will violate the aliasing rules of Rust and cause undefined
behaviors.
§Verification Design
The concrete value of a PTE is specific to the architecture and the page table configuration,
represented by the type C::E. We represent its value as an abstract EntryOwner, which is
connected to the concrete value by match_pte. The EntryOwner is well-formed with respect to
Entry if it is related to the concrete value by match_pte.
An Entry can be thought of as a mutable handle to the concrete value of the PTE.
The node field is a mutable reference to the guard of the node that contains the entry,
index provides the offset, and the pte is current value. Only one Entry can exist for
a given node at any given time.
idx: usizeThe index of the entry in the node.
node: &'a mut PageTableGuard<'rcu, C>The node that contains the entry.
Implementations§
Source§impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C>
impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C>
Sourcepub open spec fn new_spec(
pte: C::E,
idx: usize,
node: &'a mut PageTableGuard<'rcu, C>,
) -> Self
pub open spec fn new_spec( pte: C::E, idx: usize, node: &'a mut PageTableGuard<'rcu, C>, ) -> Self
{ Self { pte, idx, node } }Sourcepub exec fn new(pte: C::E, idx: usize, node: &'a mut PageTableGuard<'rcu, C>) -> res : Self
pub exec fn new(pte: C::E, idx: usize, node: &'a mut PageTableGuard<'rcu, C>) -> res : Self
res.pte == pte,res.idx == idx,*res.node == *old(node),*final(node) == *final(res.node),Source§impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C>
impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C>
Sourcepub open spec fn invariants(self, owner: EntryOwner<C>, regions: MetaRegionOwners) -> bool
pub open spec fn invariants(self, owner: EntryOwner<C>, regions: MetaRegionOwners) -> bool
{
&&& owner.inv()
&&& regions.inv()
&&& self.wf(owner)
&&& owner.metaregion_sound(regions)
}Sourcepub open spec fn node_matching(
self,
owner: EntryOwner<C>,
parent_owner: NodeOwner<C>,
guard: PageTableGuard<'rcu, C>,
) -> bool
pub open spec fn node_matching( self, owner: EntryOwner<C>, parent_owner: NodeOwner<C>, guard: PageTableGuard<'rcu, C>, ) -> bool
{
&&& parent_owner.level() == owner.parent_level
&&& parent_owner.inv()
&&& parent_owner.relate_guard(guard)
&&& owner
.match_pte(
parent_owner.children_perm.value()[self.idx as int],
owner.parent_level,
)
}Sourcepub open spec fn metaregion_sound_preserved(
regions0: MetaRegionOwners,
regions1: MetaRegionOwners,
) -> bool
pub open spec fn metaregion_sound_preserved( regions0: MetaRegionOwners, regions1: MetaRegionOwners, ) -> bool
{
OwnerSubtree::implies(
|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
entry.metaregion_sound(regions0)
},
|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
entry.metaregion_sound(regions1)
},
)
}Sourcepub open spec fn replace_nonpanic_condition(
parent_owner: NodeOwner<C>,
new_owner: EntryOwner<C>,
) -> bool
pub open spec fn replace_nonpanic_condition( parent_owner: NodeOwner<C>, new_owner: EntryOwner<C>, ) -> bool
{
if new_owner.is_node() {
parent_owner.level() - 1 == new_owner.node().level()
} else if new_owner.is_frame() {
parent_owner.level() == new_owner.parent_level
} else {
true
}
}Sourcepub open spec fn metaregion_sound_neq_preserved(
old_entry_owner: EntryOwner<C>,
new_entry_owner: EntryOwner<C>,
regions0: MetaRegionOwners,
regions1: MetaRegionOwners,
) -> bool
pub open spec fn metaregion_sound_neq_preserved( old_entry_owner: EntryOwner<C>, new_entry_owner: EntryOwner<C>, regions0: MetaRegionOwners, regions1: MetaRegionOwners, ) -> bool
{
OwnerSubtree::implies(
|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
entry.meta_slot_paddr_neq(old_entry_owner)
&& entry.meta_slot_paddr_neq(new_entry_owner)
&& entry.metaregion_sound(regions0)
},
|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
entry.metaregion_sound(regions1)
},
)
}Sourcepub open spec fn metaregion_sound_neq_old_preserved(
old_entry_owner: EntryOwner<C>,
regions0: MetaRegionOwners,
regions1: MetaRegionOwners,
) -> bool
pub open spec fn metaregion_sound_neq_old_preserved( old_entry_owner: EntryOwner<C>, regions0: MetaRegionOwners, regions1: MetaRegionOwners, ) -> bool
{
OwnerSubtree::implies(
|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
entry.meta_slot_paddr_neq(old_entry_owner)
&& entry.metaregion_sound(regions0)
},
|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
entry.metaregion_sound(regions1)
},
)
}When the new child is NOT a node, into_pte doesn’t modify raw_count.
Only paths_in_pt changes at new_idx, which metaregion_sound doesn’t inspect.
So entries with paddr_neq(old_child) preserve metaregion_sound — no
paddr_neq(new_child) needed.
Sourcepub proof fn alloc_if_none_metaregion_sound_preserved(
old_child: EntryOwner<C>,
new_child: EntryOwner<C>,
regions0: MetaRegionOwners,
regions1: MetaRegionOwners,
)
pub proof fn alloc_if_none_metaregion_sound_preserved( old_child: EntryOwner<C>, new_child: EntryOwner<C>, regions0: MetaRegionOwners, regions1: MetaRegionOwners, )
old_child.is_absent(),old_child.inv(),new_child.is_node(),regions0.inv(),regions0.contains(frame_to_index(new_child.meta_slot_paddr()->0)),regions0.slot_owner(new_child.meta_slot_paddr()->0).ref_count() == REF_COUNT_UNUSED,!crate::specs::mm::frame::meta_owners::is_mmio_paddr(new_child.meta_slot_paddr()->0),Self::metaregion_sound_neq_preserved(old_child, new_child, regions0, regions1),ensuresSelf::metaregion_sound_preserved(regions0, regions1),When alloc_if_none allocates a new node from an absent slot, all existing entries’
metaregion_sound is preserved in the new regions.
Justification: metaregion_sound_neq_preserved gives preservation for entries whose paddr
differs from both old_child and new_child. Old_child is absent (paddr_neq trivially true).
Sourcepub open spec fn path_tracked_pred_preserved(
regions0: MetaRegionOwners,
regions1: MetaRegionOwners,
) -> bool
pub open spec fn path_tracked_pred_preserved( regions0: MetaRegionOwners, regions1: MetaRegionOwners, ) -> bool
{
OwnerSubtree::implies(
PageTableOwner::<C>::path_tracked_pred(regions0),
PageTableOwner::<C>::path_tracked_pred(regions1),
)
}Sourcepub open spec fn new_owner_compatible(
self,
new_child: Child<C>,
old_owner: EntryOwner<C>,
new_owner: EntryOwner<C>,
regions: MetaRegionOwners,
) -> bool
pub open spec fn new_owner_compatible( self, new_child: Child<C>, old_owner: EntryOwner<C>, new_owner: EntryOwner<C>, regions: MetaRegionOwners, ) -> bool
{
&&& old_owner.path == new_owner.path
&&& old_owner.parent_level == new_owner.parent_level
&&& new_owner.is_node()
==> {
&&& regions.contains(frame_to_index(new_owner.meta_slot_paddr()->0))
&&& regions.slot_owner(new_owner.meta_slot_paddr()->0).ref_count()
!= REF_COUNT_UNUSED
}
}Sourcepub open spec fn parent_perms_preserved(
self,
parent_owner0: NodeOwner<C>,
parent_owner1: NodeOwner<C>,
) -> bool
pub open spec fn parent_perms_preserved( self, parent_owner0: NodeOwner<C>, parent_owner1: NodeOwner<C>, ) -> bool
{
&&& forall |i: int| {
0 <= i < NR_ENTRIES
==> (i != self.idx
==> parent_owner0.children_perm.value()[i]
== parent_owner1.children_perm.value()[i])
}
&&& parent_owner1.slot_index == parent_owner0.slot_index
&&& parent_owner1.level() == parent_owner0.level()
&&& parent_owner1.tree_level == parent_owner0.tree_level
&&& parent_owner1.meta_own.nr_children.id()
== parent_owner0.meta_own.nr_children.id()
&&& parent_owner1.meta_own.stray == parent_owner0.meta_own.stray
}Trait Implementations§
Source§impl<'a, 'rcu, C: PageTableConfig> OwnerOf for Entry<'a, 'rcu, C>
impl<'a, 'rcu, C: PageTableConfig> OwnerOf for Entry<'a, 'rcu, C>
Source§open spec fn wf(self, owner: Self::Owner) -> bool
open spec fn wf(self, owner: Self::Owner) -> bool
{
&&& self.idx < NR_ENTRIES
&&& owner.match_pte(self.pte, owner.parent_level)
&&& valid_frame_paddr(self.pte.paddr())
}Source§type Owner = EntryOwner<C>
type Owner = EntryOwner<C>
Inv, indicating that it must
has a consistent state.Auto Trait Implementations§
impl<'a, 'rcu, C> !RefUnwindSafe for Entry<'a, 'rcu, C>
impl<'a, 'rcu, C> !UnwindSafe for Entry<'a, 'rcu, C>
impl<'a, 'rcu, C> Freeze for Entry<'a, 'rcu, C>
impl<'a, 'rcu, C> Send for Entry<'a, 'rcu, C>
impl<'a, 'rcu, C> Sync for Entry<'a, 'rcu, C>
impl<'a, 'rcu, C> Unpin for Entry<'a, 'rcu, C>
impl<'a, 'rcu, C> UnsafeUnpin for Entry<'a, 'rcu, C>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T, VERUS_SPEC__A> FromSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: From<T>,
impl<T, VERUS_SPEC__A> FromSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: From<T>,
fn obeys_from_spec() -> bool
fn from_spec(v: T) -> VERUS_SPEC__A
§impl<T, VERUS_SPEC__A> IntoSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: Into<T>,
impl<T, VERUS_SPEC__A> IntoSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: Into<T>,
fn obeys_into_spec() -> bool
fn into_spec(self) -> T
§impl<T, U> IntoSpecImpl<U> for Twhere
U: From<T>,
impl<T, U> IntoSpecImpl<U> for Twhere
U: From<T>,
fn obeys_into_spec() -> bool
fn into_spec(self) -> U
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
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) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
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
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
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
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
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
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<A> SpecEq<&A> for Awhere
A: ?Sized,
impl<A> SpecEq<&mut A> for Awhere
A: ?Sized,
impl<A> SpecEq<A> for Awhere
A: ?Sized,
impl<A> SpecEq<Ghost<A>> for A
impl<A> SpecEq<Tracked<A>> for A
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.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
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.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
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.