|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH V1 7/8] x86/nestedhap: Retry nested page fault if the np2m changes during walk
From: Chunjie Zhu <chunjie.zhu@xxxxxxxxxx>
nestedhvm_hap_nested_page_fault() walks the L1 and L0 p2m tables without
holding the nested p2m lock, and only afterwards looks up the np2m with
p2m_get_nestedp2m_locked() to install the result. If L1 changes its
EPT/NPT base or the np2m is flushed or reassigned during the walk
(np2m_base / np2m_generation change), the translation computed from
the old tables may be installed into a np2m that now represents a
different L2 address space, leaving a stale or wrong mapping.
Snapshot np2m_base and np2m_generation before the walk, and re-check
them after each walk step (L1 and L0) via the new nestedhap_np2m_changed()
helper. Re-check them again, together with the np2m identity, once the
np2m lock is retaken for nestedhap_fix_p2m(). On any mismatch, drop
the lock and retry the whole fault from the start.
Signed-off-by: Chunjie Zhu <chunjie.zhu@xxxxxxxxxx>
---
xen/arch/x86/mm/hap/nested_hap.c | 40 +++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/xen/arch/x86/mm/hap/nested_hap.c b/xen/arch/x86/mm/hap/nested_hap.c
index 72706cebaedf..1f09c706dda5 100644
--- a/xen/arch/x86/mm/hap/nested_hap.c
+++ b/xen/arch/x86/mm/hap/nested_hap.c
@@ -101,6 +101,19 @@ nestedhap_fix_p2m(struct vcpu *v, struct p2m_domain *p2m,
}
}
+static bool nestedhap_np2m_changed(struct p2m_domain *p2m,
+ uint64_t base, uint64_t generation)
+{
+ bool changed;
+
+ p2m_lock(p2m);
+ changed = p2m->np2m_base != base ||
+ p2m->np2m_generation != generation;
+ p2m_unlock(p2m);
+
+ return changed;
+}
+
/* This function uses L1_gpa to walk the P2M table in L0 hypervisor. If the
* walk is successful, the translated value is returned in L0_gpa. The return
* value tells the upper level what to do.
@@ -176,16 +189,26 @@ int nestedhvm_hap_nested_page_fault(
p2m_type_t p2mt_10;
p2m_access_t p2ma_10 = p2m_access_rwx;
uint8_t p2ma_21 = p2m_access_rwx;
+ uint64_t np2m_base, np2m_generation;
if ( *L2_gpa >> v->domain->arch.cpuid->extd.maxphysaddr )
return NESTEDHVM_PAGEFAULT_INJECT;
p2m = p2m_get_hostp2m(d); /* L0 p2m */
+ retry:
+ nested_p2m = p2m_get_nestedp2m_locked(v);
+ np2m_base = nested_p2m->np2m_base;
+ np2m_generation = nested_p2m->np2m_generation;
+ p2m_unlock(nested_p2m);
+
/* walk the L1 P2M table */
rv = nhvm_hap_walk_L1_p2m(v, *L2_gpa, &L1_gpa, &page_order_21, &p2ma_21,
npfec);
+ if ( nestedhap_np2m_changed(nested_p2m, np2m_base, np2m_generation) )
+ goto retry;
+
/* let caller to handle these two cases */
switch (rv) {
case NESTEDHVM_PAGEFAULT_INJECT:
@@ -203,6 +226,9 @@ int nestedhvm_hap_nested_page_fault(
rv = nestedhap_walk_L0_p2m(p2m, L1_gpa, &L0_gpa, &p2mt_10, &p2ma_10,
&page_order_10, npfec);
+ if ( nestedhap_np2m_changed(nested_p2m, np2m_base, np2m_generation) )
+ goto retry;
+
/* let upper level caller to handle these two cases */
switch (rv) {
case NESTEDHVM_PAGEFAULT_INJECT:
@@ -249,7 +275,19 @@ int nestedhvm_hap_nested_page_fault(
p2ma_10 &= (p2m_access_t)p2ma_21;
/* fix p2m_get_pagetable(nested_p2m) */
- nested_p2m = p2m_get_nestedp2m_locked(v);
+ {
+ struct p2m_domain *current_p2m = p2m_get_nestedp2m_locked(v);
+
+ if ( current_p2m != nested_p2m ||
+ current_p2m->np2m_base != np2m_base ||
+ current_p2m->np2m_generation != np2m_generation )
+ {
+ p2m_unlock(current_p2m);
+ goto retry;
+ }
+
+ nested_p2m = current_p2m;
+ }
nestedhap_fix_p2m(v, nested_p2m, *L2_gpa, L0_gpa, page_order_20,
p2mt_10, p2ma_10);
p2m_unlock(nested_p2m);
--
2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |