pub struct Entry<'rcu, C: PageTableConfig> {
pub pte: C::E,
pub idx: usize,
pub node: PPtr<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.
idx: usizeThe index of the entry in the node.
node: PPtr<PageTableGuard<'rcu, C>>The node that contains the entry.
Implementations§
Source§impl<'rcu, C: PageTableConfig> Entry<'rcu, C>
impl<'rcu, C: PageTableConfig> Entry<'rcu, C>
Sourcepub open spec fn new_spec(
pte: C::E,
idx: usize,
node: PPtr<PageTableGuard<'rcu, C>>,
) -> Self
pub open spec fn new_spec( pte: C::E, idx: usize, node: PPtr<PageTableGuard<'rcu, C>>, ) -> Self
{ Self { pte, idx, node } }Sourcepub exec fn new(pte: C::E, idx: usize, node: PPtr<PageTableGuard<'rcu, C>>) -> Self
pub exec fn new(pte: C::E, idx: usize, node: PPtr<PageTableGuard<'rcu, C>>) -> Self
Source§impl<'a, 'rcu, C: PageTableConfig> Entry<'rcu, C>
impl<'a, 'rcu, C: PageTableConfig> Entry<'rcu, C>
Sourcepub exec fn is_node(&self) -> bool
pub exec fn is_node(&self) -> bool
Tracked(owner): Tracked <EntryOwner <C>>,
Tracked(parent_owner): Tracked <& NodeOwner <C>>,
Tracked(guard_perm): Tracked <& GuardPerm <'rcu,C>>,requiresowner.inv(),self.wf(owner),guard_perm.addr() == self.node.addr(),parent_owner.relate_guard_perm(*guard_perm),parent_owner.inv(),Returns if the entry maps to a page table node.
Sourcepub exec fn to_ref(&self) -> res : ChildRef<'rcu, C>
pub exec fn to_ref(&self) -> res : ChildRef<'rcu, C>
Tracked(owner): Tracked <& EntryOwner <C>>,
Tracked(parent_owner): Tracked <& NodeOwner <C>>,
Tracked(regions): Tracked <& mut MetaRegionOwners>,
Tracked(guard_perm): Tracked <& GuardPerm <'rcu,C>>,requiresself.wf(*owner),owner.inv(),old(regions).inv(),parent_owner.level == owner.parent_level,guard_perm.addr() == self.node.addr(),guard_perm.is_init(),guard_perm.value().inner.inner@.ptr.addr() == parent_owner.meta_perm.addr(),guard_perm.value().inner.inner@.ptr.addr() == parent_owner.meta_perm.points_to.addr(),guard_perm.value().inner.inner@.wf(*parent_owner),parent_owner.meta_perm.is_init(),parent_owner.meta_perm.wf(),parent_owner.inv(),owner.is_node() ==> owner.node.unwrap().relate_region(*old(regions)),ensuresregions.inv(),res.wf(*owner),owner.is_node() ==> owner.node.unwrap().relate_region(*regions),Gets a reference to the child.
Sourcepub exec fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty)
pub exec fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty)
Tracked(owner): Tracked <& mut EntryOwner <C>>,
Tracked(parent_owner): Tracked <& mut NodeOwner <C>>,
Tracked(guard_perm): Tracked <& mut GuardPerm <'rcu,C>>,requiresold(owner).inv(),old(self).wf(*old(owner)),old(parent_owner).inv(),old(self).node.addr() == old(guard_perm).addr(),old(parent_owner).relate_guard_perm(*old(guard_perm)),op.requires((old(self).pte.prop(),)),old(owner).is_frame(),ensuresowner.inv(),self.wf(*owner),parent_owner.inv(),parent_owner.relate_guard_perm(*guard_perm),guard_perm.addr() == old(guard_perm).addr(),owner.is_frame(),Operates on the mapping properties of the entry.
It only modifies the properties if the entry is present.
Sourcepub exec fn replace(&mut self, new_child: Child<C>) -> res : Child<C>
pub exec fn replace(&mut self, new_child: Child<C>) -> res : Child<C>
Tracked(regions): Tracked <& mut MetaRegionOwners>,
Tracked(owner): Tracked <& EntryOwner <C>>,
Tracked(new_owner): Tracked <& EntryOwner <C>>,
Tracked(parent_owner): Tracked <& mut NodeOwner <C>>,
Tracked(guard_perm): Tracked <& mut GuardPerm <'rcu,C>>,requiresold(self).wf(*owner),owner.inv(),new_child.wf(*new_owner),new_owner.inv(),old(parent_owner).inv(),old(regions).inv(),owner.is_node() ==> owner.node.unwrap().relate_region(*old(regions)),old(guard_perm).addr() == old(self).node.addr(),old(parent_owner).relate_guard_perm(*old(guard_perm)),ensuresparent_owner.inv(),parent_owner.relate_guard_perm(*guard_perm),guard_perm.pptr() == old(guard_perm).pptr(),guard_perm.value().inner.inner@.ptr.addr()
== old(guard_perm).value().inner.inner@.ptr.addr(),regions.inv(),self.wf(*new_owner),new_owner.inv(),res.wf(*owner),owner.is_node() ==> owner.node.unwrap().relate_region(*regions),Replaces the entry with a new child.
The old child is returned.
§Panics
The method panics if the level of the new child does not match the current node.
Sourcepub exec fn alloc_if_none<A: InAtomicMode>(
&mut self,
guard: &'rcu A,
) -> res : Option<PPtr<PageTableGuard<'rcu, C>>>
pub exec fn alloc_if_none<A: InAtomicMode>( &mut self, guard: &'rcu A, ) -> res : Option<PPtr<PageTableGuard<'rcu, C>>>
Tracked(owner): Tracked <& mut OwnerSubtree <C>>,
Tracked(regions): Tracked <& mut MetaRegionOwners>,
Tracked(guards): Tracked <& mut Guards <'rcu,C>>,
Tracked(parent_guard_perm): Tracked <& mut GuardPerm <'rcu,C>>,
->
guard_perm: Tracked <Option <GuardPerm <'rcu,C>>>,requiresold(owner).inv(),old(self).wf(old(owner).value),old(regions).inv(),ensuresold(owner).value.is_absent()
==> {
&&& res is Some
&&& owner.value.is_node()
&&& guard_perm@ is Some
&&& guard_perm@.unwrap().addr() == res.unwrap().addr()
&&& owner.level == old(owner).level
&&& owner.value.parent_level == old(owner).value.parent_level
&&& owner.value.node.unwrap().relate_guard_perm(guard_perm@.unwrap())
},!old(owner).value.is_absent()
==> {
&&& res is None
&&& *owner == *old(owner)
},forall |i: usize| old(guards).lock_held(i) ==> guards.lock_held(i),parent_guard_perm.addr() == old(parent_guard_perm).addr(),parent_guard_perm.is_init(),parent_guard_perm.value().inner.inner@.ptr.addr()
== old(parent_guard_perm).value().inner.inner@.ptr.addr(),owner.inv(),regions.inv(),Allocates a new child page table node and replaces the entry with it.
If the old entry is not none, the operation will fail and return None.
Otherwise, the lock guard of the new child page table node is returned.
Sourcepub exec fn split_if_mapped_huge<A: InAtomicMode>(
&mut self,
guard: &'rcu A,
) -> res : Option<PPtr<PageTableGuard<'rcu, C>>>
pub exec fn split_if_mapped_huge<A: InAtomicMode>( &mut self, guard: &'rcu A, ) -> res : Option<PPtr<PageTableGuard<'rcu, C>>>
Tracked(owner): Tracked <& mut OwnerSubtree <C>>,
Tracked(parent_owner): Tracked <& mut NodeOwner <C>>,
Tracked(regions): Tracked <& mut MetaRegionOwners>,
Tracked(guards): Tracked <& mut Guards <'rcu,C>>,
Tracked(guard_perm): Tracked <& mut GuardPerm <'rcu,C>>,requiresold(regions).inv(),old(owner).inv(),old(self).wf(old(owner).value),old(self).node.addr() == old(guard_perm).addr(),old(guard_perm).is_init(),old(parent_owner).relate_guard_perm(*old(guard_perm)),old(parent_owner).inv(),ensuresold(owner).value.is_frame()
==> {
&&& res is Some
&&& owner.value.is_node()
&&& owner.level == old(owner).level
&&& parent_owner.relate_guard_perm(*guard_perm)
&&& guards.guards.contains_key(res.unwrap().addr())
&&& guards.guards[res.unwrap().addr()] is Some
&&& guards.guards[res.unwrap().addr()].unwrap().pptr() == res.unwrap()
&&& owner
.value
.node
.unwrap()
.relate_guard_perm(guards.guards[res.unwrap().addr()].unwrap())
&&& owner.value.node.unwrap().meta_perm.addr() == res.unwrap().addr()
},!old(owner).value.is_frame()
==> {
&&& res is None
&&& *owner == *old(owner)
},owner.inv(),regions.inv(),parent_owner.inv(),guard_perm.pptr() == old(guard_perm).pptr(),guard_perm.value().inner.inner@.ptr.addr()
== old(guard_perm).value().inner.inner@.ptr.addr(),Splits the entry to smaller pages if it maps to a huge page.
If the entry does map to a huge page, it is split into smaller pages mapped by a child page table node. The new child page table node is returned.
If the entry does not map to a untracked huge page, the method returns
None.
Sourcepub exec fn new_at(guard: PPtr<PageTableGuard<'rcu, C>>, idx: usize) -> res : Self
pub exec fn new_at(guard: PPtr<PageTableGuard<'rcu, C>>, idx: usize) -> res : Self
Tracked(owner): Tracked <& EntryOwner <C>>,
Tracked(parent_owner): Tracked <& NodeOwner <C>>,
Tracked(guard_perm): Tracked <& GuardPerm <'rcu,C>>,requiresowner.inv(),parent_owner.inv(),guard_perm.addr() == guard.addr(),parent_owner.relate_guard_perm(*guard_perm),idx < NR_ENTRIES(),owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),ensuresres.wf(*owner),res.node.addr() == guard_perm.addr(),Create a new entry at the node with guard.
§Safety
The caller must ensure that the index is within the bounds of the node.
Trait Implementations§
Source§impl<'rcu, C: PageTableConfig> OwnerOf for Entry<'rcu, C>
impl<'rcu, C: PageTableConfig> OwnerOf for Entry<'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)
&&& self.pte.paddr() % PAGE_SIZE() == 0
&&& self.pte.paddr() < MAX_PADDR()
}Source§type Owner = EntryOwner<C>
type Owner = EntryOwner<C>
Inv, indicating that it must
has a consistent state.