@@ -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