make_cr3(v, cr3_mfn);
}
-static inline void page_set_tlbflush_timestamp(struct page_info *page)
+static inline void set_tlbflush_timestamp(struct page_info *page)
{
/*
* Record TLB information for flush later. We do not stamp page tables
*/
if ( !(page->count_info & PGC_page_table) ||
!shadow_mode_enabled(page_get_owner(page)) )
- page->tlbflush_timestamp = tlbflush_current_time();
+ page_set_tlbflush_timestamp(page);
}
const char __section(".bss.page_aligned.const") __aligned(PAGE_SIZE)
dec_linear_entries(ptpg);
}
ASSERT(!page->linear_pt_count || page_get_owner(page)->is_dying);
- page_set_tlbflush_timestamp(page);
+ set_tlbflush_timestamp(page);
smp_wmb();
page->u.inuse.type_info--;
}
{
ASSERT((page->u.inuse.type_info &
(PGT_count_mask|PGT_validated|PGT_partial)) == 1);
- page_set_tlbflush_timestamp(page);
+ set_tlbflush_timestamp(page);
smp_wmb();
page->u.inuse.type_info |= PGT_validated;
}
if ( ptpg && PGT_type_equal(x, ptpg->u.inuse.type_info) )
{
/*
- * page_set_tlbflush_timestamp() accesses the same union
+ * set_tlbflush_timestamp() accesses the same union
* linear_pt_count lives in. Unvalidated page table pages,
* however, should occur during domain destruction only
* anyway. Updating of linear_pt_count luckily is not
ptpg = NULL;
}
- page_set_tlbflush_timestamp(page);
+ set_tlbflush_timestamp(page);
}
if ( likely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) == x) )
* TLBs when we reuse the page. Because the destructors leave the
* contents of the pages in place, we can delay TLB flushes until
* just before the allocator hands the page out again. */
- sp->tlbflush_timestamp = tlbflush_current_time();
+ page_set_tlbflush_timestamp(sp);
perfc_decr(shadow_alloc_count);
page_list_add_tail(sp, &d->arch.paging.shadow.freelist);
sp = next;
/* If a page has no owner it will need no safety TLB flush. */
pg[i].u.free.need_tlbflush = (page_get_owner(&pg[i]) != NULL);
if ( pg[i].u.free.need_tlbflush )
- pg[i].tlbflush_timestamp = tlbflush_current_time();
+ page_set_tlbflush_timestamp(&pg[i]);
/* This page is not a guest frame any more. */
page_set_owner(&pg[i], NULL); /* set_gpfn_from_mfn snoops pg owner */
#define tlbflush_current_time() (0)
+static inline void page_set_tlbflush_timestamp(struct page_info *page)
+{
+ page->tlbflush_timestamp = tlbflush_current_time();
+}
+
#if defined(CONFIG_ARM_32)
# include <asm/arm32/flushtlb.h>
#elif defined(CONFIG_ARM_64)
#define tlbflush_current_time() tlbflush_clock
+static inline void page_set_tlbflush_timestamp(struct page_info *page)
+{
+ /*
+ * Prevent storing a stale time stamp, which could happen if an update
+ * to tlbflush_clock plus a subsequent flush IPI happen between the
+ * reading of tlbflush_clock and the writing of the struct page_info
+ * field.
+ */
+ ASSERT(local_irq_is_enabled());
+ local_irq_disable();
+ page->tlbflush_timestamp = tlbflush_current_time();
+ local_irq_enable();
+}
+
/*
* @cpu_stamp is the timestamp at last TLB flush for the CPU we are testing.
* @lastuse_stamp is a timestamp taken when the PFN we are testing was last