Skip to content

Commit 5bd5e2a

Browse files
committed
Add query
1 parent dfcb2c0 commit 5bd5e2a

1 file changed

Lines changed: 78 additions & 0 deletions

File tree

  • lock-protocol/src/mm/page_table/cursor

lock-protocol/src/mm/page_table/cursor/mod.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,84 @@ impl<'a, C: PageTableConfig> Cursor<'a, C> {
271271
Ok(locking::lock_range(pt, va))
272272
}
273273

274+
/// Queries the mapping at the current virtual address.
275+
///
276+
/// If the cursor is pointing to a valid virtual address that is locked,
277+
/// it will return the virtual address range and the item at that slot.
278+
pub fn query(&mut self, Tracked(spt): Tracked<&SubPageTable<C>>) -> (res: Result<
279+
Option<(Paddr, PagingLevel, PageProperty)>,
280+
PageTableError,
281+
>)
282+
requires
283+
old(self).wf(spt),
284+
ensures
285+
self.wf(spt),
286+
match res {
287+
Ok(Some(item)) => {
288+
exists|pte_pa: Paddr|
289+
{
290+
&&& #[trigger] spt.ptes.value().contains_key(pte_pa as int)
291+
&&& #[trigger] spt.ptes.value()[pte_pa as int].map_to_pa == item.0
292+
}
293+
},
294+
Ok(None) => true, // Maybe && forall spt.ptes.value()[pte_pa as int].va != self.va
295+
Err(err) => {
296+
&&& old(self).va >= self.barrier_va.end
297+
&&& err == PageTableError::InvalidVaddr(old(self).va)
298+
},
299+
},
300+
{
301+
if self.va >= self.barrier_va.end {
302+
return Err(PageTableError::InvalidVaddr(self.va));
303+
}
304+
let ghost cur_va = self.va;
305+
306+
let rcu_guard = self.preempt_guard;
307+
308+
loop
309+
invariant
310+
self.wf(spt),
311+
self.constant_fields_unchanged(old(self), spt, spt),
312+
self.va == old(self).va,
313+
decreases self.level,
314+
{
315+
let level = self.level;
316+
let ghost cur_level = self.level;
317+
318+
let cur_entry = self.cur_entry(Tracked(spt));
319+
let item = match cur_entry.to_ref(Tracked(spt)) {
320+
ChildRef::PageTable(pt) => {
321+
let guard = pt.make_guard_unchecked(
322+
rcu_guard,
323+
Ghost(align_down(cur_va, page_size::<C>(cur_level))),
324+
);
325+
self.push_level(guard, Tracked(spt));
326+
continue ;
327+
},
328+
ChildRef::None => None,
329+
ChildRef::Frame(pa, ch_level, prop) => {
330+
// debug_assert_eq!(ch_level, level);
331+
// SAFETY:
332+
// This is part of (if `split_huge` happens) a page table item mapped
333+
// with a previous call to `C::item_into_raw`, where:
334+
// - The physical address and the paging level match it;
335+
// - The item part is still mapped so we don't take its ownership.
336+
//
337+
// For page table configs that require the `AVAIL1` flag to be kept
338+
// (currently, only kernel page tables), the callers of the unsafe
339+
// `protect_next` method uphold this invariant.
340+
// let item = core::mem::ManuallyDrop::new(
341+
// unsafe { C::item_from_raw(pa, level, prop, Tracked(&spt.alloc_model)) },
342+
// );
343+
// TODO: Provide a `PageTableItemRef` to reduce copies.
344+
Some((pa, ch_level, prop))
345+
},
346+
};
347+
348+
return Ok(item);
349+
}
350+
}
351+
274352
/// Traverses forward in the current level to the next PTE.
275353
///
276354
/// If reached the end of a page table node, it leads itself up to the next page of the parent

0 commit comments

Comments
 (0)