|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH V1 2/8] x86/nestedvmx: Implement nhvm_hap_walk_L1_p2m2
From: Chunjie Zhu <chunjie.zhu@xxxxxxxxxx>
p2m_get_page_from_gfn() on a nested p2m calls
nestedhvm_hap_nested_page_fault2(), which walks L1's paging structures via
hvm_funcs.nhvm_hap_walk_L1_p2m2. Only SVM provides this hook. On VMX it
is NULL, so the alternative_call() ends up as a #UD in L0 and the host
panics.
It is reachable from an L2 guest. An EPT violation on MMIO makes L0
emulate the access, and the emulator walks L2's pagetables through the
nested p2m.
nhvm_hap_walk_L1_p2m2
nestedhvm_hap_nested_page_fault2
p2m_get_page_from_gfn
hap_p2m_ga_to_gfn_4_levels
paging_gva_to_gfn
hvmemul_map_linear_addr
hvmemul_write
hvm_hap_nested_page_fault
Signed-off-by: Chunjie Zhu <chunjie.zhu@xxxxxxxxxx>
---
xen/arch/x86/hvm/vmx/vmx.c | 1 +
xen/arch/x86/hvm/vmx/vvmx.c | 39 ++++++++++++++++++++++++-
xen/arch/x86/include/asm/hvm/vmx/vvmx.h | 7 ++++-
xen/arch/x86/mm/hap/nested_ept.c | 10 +++----
4 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 3c7374a9ff42..ed4ff56e7797 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -2892,6 +2892,7 @@ static struct hvm_function_table __initdata_cf_clobber
vmx_function_table = {
.nhvm_domain_relinquish_resources = nvmx_domain_relinquish_resources,
.update_vlapic_mode = vmx_vlapic_msr_changed,
.nhvm_hap_walk_L1_p2m = nvmx_hap_walk_L1_p2m,
+ .nhvm_hap_walk_L1_p2m2 = nvmx_hap_walk_L1_p2m2,
#ifdef CONFIG_VM_EVENT
.enable_msr_interception = vmx_enable_msr_interception,
#endif
diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c
index 29e48387a110..8d6e0c66f38e 100644
--- a/xen/arch/x86/hvm/vmx/vvmx.c
+++ b/xen/arch/x86/hvm/vmx/vvmx.c
@@ -2355,7 +2355,8 @@ int cf_check nvmx_hap_walk_L1_p2m(
vmx_vmcs_enter(v);
__vmread(EXIT_QUALIFICATION, &exit_qual);
- rc = nept_translate_l2ga(v, L2_gpa, page_order, rwx_rights, &gfn, p2m_acc,
+ rc = nept_translate_l2ga(v->domain, nhvm_vcpu_p2m_base(v), L2_gpa,
+ page_order, rwx_rights, &gfn, p2m_acc,
&exit_qual, &exit_reason);
switch ( rc )
{
@@ -2383,6 +2384,42 @@ int cf_check nvmx_hap_walk_L1_p2m(
return rc;
}
+/*
+ * As nvmx_hap_walk_L1_p2m(), for a walk of a specific nested p2m that is not
+ * tied to a VM exit (e.g. L0 emulation reading L2's pagetables). There is
+ * no EPT violation to reflect to L1, so only the result is reported.
+ */
+int cf_check nvmx_hap_walk_L1_p2m2(
+ struct p2m_domain *nested_p2m, paddr_t L2_gpa, paddr_t *L1_gpa,
+ unsigned int *page_order, uint8_t *p2m_acc, struct npfec npfec)
+{
+ unsigned long gfn;
+ uint64_t exit_qual = 0;
+ uint32_t exit_reason;
+ uint32_t rwx_rights =
+ (npfec.insn_fetch << 2) | (npfec.write_access << 1) |
npfec.read_access;
+
+ switch ( nept_translate_l2ga(nested_p2m->domain, nested_p2m->np2m_base,
+ L2_gpa, page_order, rwx_rights, &gfn,
+ p2m_acc, &exit_qual, &exit_reason) )
+ {
+ case EPT_TRANSLATE_SUCCEED:
+ *L1_gpa = (gfn << PAGE_SHIFT) + (L2_gpa & ~PAGE_MASK);
+ return NESTEDHVM_PAGEFAULT_DONE;
+
+ case EPT_TRANSLATE_VIOLATION:
+ case EPT_TRANSLATE_MISCONFIG:
+ return NESTEDHVM_PAGEFAULT_INJECT;
+
+ case EPT_TRANSLATE_RETRY:
+ return NESTEDHVM_PAGEFAULT_RETRY;
+
+ default:
+ gdprintk(XENLOG_ERR, "GUEST EPT translation error!\n");
+ BUG();
+ }
+}
+
void nvmx_idtv_handling(void)
{
struct vcpu *v = current;
diff --git a/xen/arch/x86/include/asm/hvm/vmx/vvmx.h
b/xen/arch/x86/include/asm/hvm/vmx/vvmx.h
index da10d3fa9617..2e0ac5798d5d 100644
--- a/xen/arch/x86/include/asm/hvm/vmx/vvmx.h
+++ b/xen/arch/x86/include/asm/hvm/vmx/vvmx.h
@@ -89,9 +89,14 @@ bool cf_check nvmx_ept_enabled(struct vcpu *v);
#define EPT_TRANSLATE_MISCONFIG 2
#define EPT_TRANSLATE_RETRY 3
+struct p2m_domain;
+
int cf_check nvmx_hap_walk_L1_p2m(
struct vcpu *v, paddr_t L2_gpa, paddr_t *L1_gpa, unsigned int *page_order,
uint8_t *p2m_acc, struct npfec npfec);
+int cf_check nvmx_hap_walk_L1_p2m2(
+ struct p2m_domain *nested_p2m, paddr_t L2_gpa, paddr_t *L1_gpa,
+ unsigned int *page_order, uint8_t *p2m_acc, struct npfec npfec);
/*
* Virtual VMCS layout
@@ -193,7 +198,7 @@ void nvmx_set_cr_read_shadow(struct vcpu *v, unsigned int
cr);
uint64_t nept_get_ept_vpid_cap(void);
-int nept_translate_l2ga(struct vcpu *v, paddr_t l2ga,
+int nept_translate_l2ga(struct domain *d, uint64_t eptp_base, paddr_t l2ga,
unsigned int *page_order, uint32_t rwx_acc,
unsigned long *l1gfn, uint8_t *p2m_acc,
uint64_t *exit_qual, uint32_t *exit_reason);
diff --git a/xen/arch/x86/mm/hap/nested_ept.c b/xen/arch/x86/mm/hap/nested_ept.c
index e116d8254824..f8563156b6d0 100644
--- a/xen/arch/x86/mm/hap/nested_ept.c
+++ b/xen/arch/x86/mm/hap/nested_ept.c
@@ -136,13 +136,13 @@ static int ept_lvl_table_offset(unsigned long gpa, int
lvl)
}
static uint32_t
-nept_walk_tables(struct vcpu *v, unsigned long l2ga, ept_walk_t *gw)
+nept_walk_tables(struct domain *d, uint64_t eptp_base, unsigned long l2ga,
+ ept_walk_t *gw)
{
int lvl;
uint32_t rc = 0, ret = 0, gflags;
- struct domain *d = v->domain;
struct p2m_domain *p2m = d->arch.p2m;
- gfn_t base_gfn = _gfn(nhvm_vcpu_p2m_base(v) >> PAGE_SHIFT);
+ gfn_t base_gfn = _gfn(eptp_base >> PAGE_SHIFT);
mfn_t lxmfn;
ept_entry_t *lxp = NULL;
@@ -209,7 +209,7 @@ out:
/* Translate a L2 guest address to L1 gpa via L1 EPT paging structure */
-int nept_translate_l2ga(struct vcpu *v, paddr_t l2ga,
+int nept_translate_l2ga(struct domain *d, uint64_t eptp_base, paddr_t l2ga,
unsigned int *page_order, uint32_t rwx_acc,
unsigned long *l1gfn, uint8_t *p2m_acc,
uint64_t *exit_qual, uint32_t *exit_reason)
@@ -220,7 +220,7 @@ int nept_translate_l2ga(struct vcpu *v, paddr_t l2ga,
*l1gfn = gfn_x(INVALID_GFN);
- rc = nept_walk_tables(v, l2ga, &gw);
+ rc = nept_walk_tables(d, eptp_base, l2ga, &gw);
switch ( rc )
{
case EPT_TRANSLATE_SUCCEED:
--
2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |