* [PATCH v6 1/3] KVM: vmx: Enable VMFUNCs
2017-08-01 23:24 [PATCH v6 0/3] Expose VMFUNC to the nested hypervisor Bandan Das
@ 2017-08-01 23:24 ` Bandan Das
2017-08-01 23:24 ` [PATCH v6 2/3] KVM: nVMX: Enable VMFUNC for the L1 hypervisor Bandan Das
2017-08-01 23:24 ` [PATCH 3/3] KVM: nVMX: Emulate EPTP switching " Bandan Das
2 siblings, 0 replies; 8+ messages in thread
From: Bandan Das @ 2017-08-01 23:24 UTC (permalink / raw)
To: kvm; +Cc: pbonzini, david, rkrcmar, jmattson, linux-kernel
Enable VMFUNC in the secondary execution controls. This simplifies the
changes necessary to expose it to nested hypervisors. VMFUNCs still
cause #UD when invoked.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Bandan Das <bsd@redhat.com>
---
arch/x86/include/asm/vmx.h | 3 +++
arch/x86/kvm/vmx.c | 22 +++++++++++++++++++++-
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 35cd06f..da5375e 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -72,6 +72,7 @@
#define SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400
#define SECONDARY_EXEC_RDRAND 0x00000800
#define SECONDARY_EXEC_ENABLE_INVPCID 0x00001000
+#define SECONDARY_EXEC_ENABLE_VMFUNC 0x00002000
#define SECONDARY_EXEC_SHADOW_VMCS 0x00004000
#define SECONDARY_EXEC_RDSEED 0x00010000
#define SECONDARY_EXEC_ENABLE_PML 0x00020000
@@ -187,6 +188,8 @@ enum vmcs_field {
APIC_ACCESS_ADDR_HIGH = 0x00002015,
POSTED_INTR_DESC_ADDR = 0x00002016,
POSTED_INTR_DESC_ADDR_HIGH = 0x00002017,
+ VM_FUNCTION_CONTROL = 0x00002018,
+ VM_FUNCTION_CONTROL_HIGH = 0x00002019,
EPT_POINTER = 0x0000201a,
EPT_POINTER_HIGH = 0x0000201b,
EOI_EXIT_BITMAP0 = 0x0000201c,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 39a6222..b8969da 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1318,6 +1318,12 @@ static inline bool cpu_has_vmx_tsc_scaling(void)
SECONDARY_EXEC_TSC_SCALING;
}
+static inline bool cpu_has_vmx_vmfunc(void)
+{
+ return vmcs_config.cpu_based_2nd_exec_ctrl &
+ SECONDARY_EXEC_ENABLE_VMFUNC;
+}
+
static inline bool report_flexpriority(void)
{
return flexpriority_enabled;
@@ -3607,7 +3613,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
SECONDARY_EXEC_SHADOW_VMCS |
SECONDARY_EXEC_XSAVES |
SECONDARY_EXEC_ENABLE_PML |
- SECONDARY_EXEC_TSC_SCALING;
+ SECONDARY_EXEC_TSC_SCALING |
+ SECONDARY_EXEC_ENABLE_VMFUNC;
if (adjust_vmx_controls(min2, opt2,
MSR_IA32_VMX_PROCBASED_CTLS2,
&_cpu_based_2nd_exec_control) < 0)
@@ -5303,6 +5310,9 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmcs_writel(HOST_GS_BASE, 0); /* 22.2.4 */
#endif
+ if (cpu_has_vmx_vmfunc())
+ vmcs_write64(VM_FUNCTION_CONTROL, 0);
+
vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host));
@@ -7793,6 +7803,12 @@ static int handle_preemption_timer(struct kvm_vcpu *vcpu)
return 1;
}
+static int handle_vmfunc(struct kvm_vcpu *vcpu)
+{
+ kvm_queue_exception(vcpu, UD_VECTOR);
+ return 1;
+}
+
/*
* The exit handlers return 1 if the exit was handled fully and guest execution
* may resume. Otherwise they set the kvm_run parameter to indicate what needs
@@ -7843,6 +7859,7 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[EXIT_REASON_XSAVES] = handle_xsaves,
[EXIT_REASON_XRSTORS] = handle_xrstors,
[EXIT_REASON_PML_FULL] = handle_pml_full,
+ [EXIT_REASON_VMFUNC] = handle_vmfunc,
[EXIT_REASON_PREEMPTION_TIMER] = handle_preemption_timer,
};
@@ -8164,6 +8181,9 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
case EXIT_REASON_PML_FULL:
/* We emulate PML support to L1. */
return false;
+ case EXIT_REASON_VMFUNC:
+ /* VM functions are emulated through L2->L0 vmexits. */
+ return false;
default:
return true;
}
--
2.9.4
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v6 2/3] KVM: nVMX: Enable VMFUNC for the L1 hypervisor
2017-08-01 23:24 [PATCH v6 0/3] Expose VMFUNC to the nested hypervisor Bandan Das
2017-08-01 23:24 ` [PATCH v6 1/3] KVM: vmx: Enable VMFUNCs Bandan Das
@ 2017-08-01 23:24 ` Bandan Das
2017-08-01 23:24 ` [PATCH 3/3] KVM: nVMX: Emulate EPTP switching " Bandan Das
2 siblings, 0 replies; 8+ messages in thread
From: Bandan Das @ 2017-08-01 23:24 UTC (permalink / raw)
To: kvm; +Cc: pbonzini, david, rkrcmar, jmattson, linux-kernel
Expose VMFUNC in MSRs and VMCS fields. No actual VMFUNCs are enabled.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Bandan Das <bsd@redhat.com>
---
arch/x86/kvm/vmx.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index b8969da..042ea88 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -243,6 +243,7 @@ struct __packed vmcs12 {
u64 virtual_apic_page_addr;
u64 apic_access_addr;
u64 posted_intr_desc_addr;
+ u64 vm_function_control;
u64 ept_pointer;
u64 eoi_exit_bitmap0;
u64 eoi_exit_bitmap1;
@@ -484,6 +485,7 @@ struct nested_vmx {
u64 nested_vmx_cr4_fixed0;
u64 nested_vmx_cr4_fixed1;
u64 nested_vmx_vmcs_enum;
+ u64 nested_vmx_vmfunc_controls;
};
#define POSTED_INTR_ON 0
@@ -766,6 +768,7 @@ static const unsigned short vmcs_field_to_offset_table[] = {
FIELD64(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr),
FIELD64(APIC_ACCESS_ADDR, apic_access_addr),
FIELD64(POSTED_INTR_DESC_ADDR, posted_intr_desc_addr),
+ FIELD64(VM_FUNCTION_CONTROL, vm_function_control),
FIELD64(EPT_POINTER, ept_pointer),
FIELD64(EOI_EXIT_BITMAP0, eoi_exit_bitmap0),
FIELD64(EOI_EXIT_BITMAP1, eoi_exit_bitmap1),
@@ -1398,6 +1401,11 @@ static inline bool nested_cpu_has_posted_intr(struct vmcs12 *vmcs12)
return vmcs12->pin_based_vm_exec_control & PIN_BASED_POSTED_INTR;
}
+static inline bool nested_cpu_has_vmfunc(struct vmcs12 *vmcs12)
+{
+ return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_VMFUNC);
+}
+
static inline bool is_nmi(u32 intr_info)
{
return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
@@ -2807,6 +2815,12 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
} else
vmx->nested.nested_vmx_ept_caps = 0;
+ if (cpu_has_vmx_vmfunc()) {
+ vmx->nested.nested_vmx_secondary_ctls_high |=
+ SECONDARY_EXEC_ENABLE_VMFUNC;
+ vmx->nested.nested_vmx_vmfunc_controls = 0;
+ }
+
/*
* Old versions of KVM use the single-context version without
* checking for support, so declare that it is supported even
@@ -3176,6 +3190,9 @@ static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
*pdata = vmx->nested.nested_vmx_ept_caps |
((u64)vmx->nested.nested_vmx_vpid_caps << 32);
break;
+ case MSR_IA32_VMX_VMFUNC:
+ *pdata = vmx->nested.nested_vmx_vmfunc_controls;
+ break;
default:
return 1;
}
@@ -7805,7 +7822,29 @@ static int handle_preemption_timer(struct kvm_vcpu *vcpu)
static int handle_vmfunc(struct kvm_vcpu *vcpu)
{
- kvm_queue_exception(vcpu, UD_VECTOR);
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ struct vmcs12 *vmcs12;
+ u32 function = vcpu->arch.regs[VCPU_REGS_RAX];
+
+ /*
+ * VMFUNC is only supported for nested guests, but we always enable the
+ * secondary control for simplicity; for non-nested mode, fake that we
+ * didn't by injecting #UD.
+ */
+ if (!is_guest_mode(vcpu)) {
+ kvm_queue_exception(vcpu, UD_VECTOR);
+ return 1;
+ }
+
+ vmcs12 = get_vmcs12(vcpu);
+ if ((vmcs12->vm_function_control & (1 << function)) == 0)
+ goto fail;
+ WARN_ONCE(1, "VMCS12 VM function control should have been zero");
+
+fail:
+ nested_vmx_vmexit(vcpu, vmx->exit_reason,
+ vmcs_read32(VM_EXIT_INTR_INFO),
+ vmcs_readl(EXIT_QUALIFICATION));
return 1;
}
@@ -10133,7 +10172,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
exec_control &= ~(SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
SECONDARY_EXEC_RDTSCP |
SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
- SECONDARY_EXEC_APIC_REGISTER_VIRT);
+ SECONDARY_EXEC_APIC_REGISTER_VIRT |
+ SECONDARY_EXEC_ENABLE_VMFUNC);
if (nested_cpu_has(vmcs12,
CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)) {
vmcs12_exec_ctrl = vmcs12->secondary_vm_exec_control &
@@ -10141,6 +10181,10 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
exec_control |= vmcs12_exec_ctrl;
}
+ /* All VMFUNCs are currently emulated through L0 vmexits. */
+ if (exec_control & SECONDARY_EXEC_ENABLE_VMFUNC)
+ vmcs_write64(VM_FUNCTION_CONTROL, 0);
+
if (exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY) {
vmcs_write64(EOI_EXIT_BITMAP0,
vmcs12->eoi_exit_bitmap0);
@@ -10393,6 +10437,11 @@ static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
vmx->nested.nested_vmx_entry_ctls_high))
return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
+ if (nested_cpu_has_vmfunc(vmcs12) &&
+ (vmcs12->vm_function_control &
+ ~vmx->nested.nested_vmx_vmfunc_controls))
+ return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
+
if (vmcs12->cr3_target_count > nested_cpu_vmx_misc_cr3_count(vcpu))
return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
--
2.9.4
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 3/3] KVM: nVMX: Emulate EPTP switching for the L1 hypervisor
2017-08-01 23:24 [PATCH v6 0/3] Expose VMFUNC to the nested hypervisor Bandan Das
2017-08-01 23:24 ` [PATCH v6 1/3] KVM: vmx: Enable VMFUNCs Bandan Das
2017-08-01 23:24 ` [PATCH v6 2/3] KVM: nVMX: Enable VMFUNC for the L1 hypervisor Bandan Das
@ 2017-08-01 23:24 ` Bandan Das
2017-08-03 11:39 ` David Hildenbrand
2 siblings, 1 reply; 8+ messages in thread
From: Bandan Das @ 2017-08-01 23:24 UTC (permalink / raw)
To: kvm; +Cc: pbonzini, david, rkrcmar, jmattson, linux-kernel
When L2 uses vmfunc, L0 utilizes the associated vmexit to
emulate a switching of the ept pointer by reloading the
guest MMU.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Bandan Das <bsd@redhat.com>
---
arch/x86/include/asm/vmx.h | 6 +++
arch/x86/kvm/vmx.c | 130 ++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 130 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index da5375e..5f63a2e 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -115,6 +115,10 @@
#define VMX_MISC_SAVE_EFER_LMA 0x00000020
#define VMX_MISC_ACTIVITY_HLT 0x00000040
+/* VMFUNC functions */
+#define VMX_VMFUNC_EPTP_SWITCHING 0x00000001
+#define VMFUNC_EPTP_ENTRIES 512
+
static inline u32 vmx_basic_vmcs_revision_id(u64 vmx_basic)
{
return vmx_basic & GENMASK_ULL(30, 0);
@@ -200,6 +204,8 @@ enum vmcs_field {
EOI_EXIT_BITMAP2_HIGH = 0x00002021,
EOI_EXIT_BITMAP3 = 0x00002022,
EOI_EXIT_BITMAP3_HIGH = 0x00002023,
+ EPTP_LIST_ADDRESS = 0x00002024,
+ EPTP_LIST_ADDRESS_HIGH = 0x00002025,
VMREAD_BITMAP = 0x00002026,
VMWRITE_BITMAP = 0x00002028,
XSS_EXIT_BITMAP = 0x0000202C,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 042ea88..7235e9a 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -249,6 +249,7 @@ struct __packed vmcs12 {
u64 eoi_exit_bitmap1;
u64 eoi_exit_bitmap2;
u64 eoi_exit_bitmap3;
+ u64 eptp_list_address;
u64 xss_exit_bitmap;
u64 guest_physical_address;
u64 vmcs_link_pointer;
@@ -774,6 +775,7 @@ static const unsigned short vmcs_field_to_offset_table[] = {
FIELD64(EOI_EXIT_BITMAP1, eoi_exit_bitmap1),
FIELD64(EOI_EXIT_BITMAP2, eoi_exit_bitmap2),
FIELD64(EOI_EXIT_BITMAP3, eoi_exit_bitmap3),
+ FIELD64(EPTP_LIST_ADDRESS, eptp_list_address),
FIELD64(XSS_EXIT_BITMAP, xss_exit_bitmap),
FIELD64(GUEST_PHYSICAL_ADDRESS, guest_physical_address),
FIELD64(VMCS_LINK_POINTER, vmcs_link_pointer),
@@ -1406,6 +1408,13 @@ static inline bool nested_cpu_has_vmfunc(struct vmcs12 *vmcs12)
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_VMFUNC);
}
+static inline bool nested_cpu_has_eptp_switching(struct vmcs12 *vmcs12)
+{
+ return nested_cpu_has_vmfunc(vmcs12) &&
+ (vmcs12->vm_function_control &
+ VMX_VMFUNC_EPTP_SWITCHING);
+}
+
static inline bool is_nmi(u32 intr_info)
{
return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
@@ -2818,7 +2827,12 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
if (cpu_has_vmx_vmfunc()) {
vmx->nested.nested_vmx_secondary_ctls_high |=
SECONDARY_EXEC_ENABLE_VMFUNC;
- vmx->nested.nested_vmx_vmfunc_controls = 0;
+ /*
+ * Advertise EPTP switching unconditionally
+ * since we emulate it
+ */
+ vmx->nested.nested_vmx_vmfunc_controls =
+ VMX_VMFUNC_EPTP_SWITCHING;
}
/*
@@ -7820,6 +7834,94 @@ static int handle_preemption_timer(struct kvm_vcpu *vcpu)
return 1;
}
+static bool valid_ept_address(struct kvm_vcpu *vcpu, u64 address)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ u64 mask = address & 0x7;
+ int maxphyaddr = cpuid_maxphyaddr(vcpu);
+
+ /* Check for memory type validity */
+ switch (mask) {
+ case 0:
+ if (!(vmx->nested.nested_vmx_ept_caps & VMX_EPTP_UC_BIT))
+ return false;
+ break;
+ case 6:
+ if (!(vmx->nested.nested_vmx_ept_caps & VMX_EPTP_WB_BIT))
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ /* Bits 5:3 must be 3 */
+ if (((address >> VMX_EPT_GAW_EPTP_SHIFT) & 0x7) != VMX_EPT_DEFAULT_GAW)
+ return false;
+
+ /* Reserved bits should not be set */
+ if (address >> maxphyaddr || ((address >> 7) & 0x1f))
+ return false;
+
+ /* AD, if set, should be supported */
+ if ((address & VMX_EPT_AD_ENABLE_BIT)) {
+ if (!enable_ept_ad_bits)
+ return false;
+ }
+
+ return true;
+}
+
+static int nested_vmx_eptp_switching(struct kvm_vcpu *vcpu,
+ struct vmcs12 *vmcs12)
+{
+ u32 index = vcpu->arch.regs[VCPU_REGS_RCX];
+ u64 *l1_eptp_list, address;
+ struct page *page;
+ bool accessed_dirty;
+ struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
+
+ if (!nested_cpu_has_eptp_switching(vmcs12) ||
+ !nested_cpu_has_ept(vmcs12))
+ return 1;
+
+ if (index >= VMFUNC_EPTP_ENTRIES)
+ return 1;
+
+ page = nested_get_page(vcpu, vmcs12->eptp_list_address);
+ if (!page)
+ return 1;
+
+ l1_eptp_list = kmap(page);
+ address = l1_eptp_list[index];
+ accessed_dirty = !!(address & VMX_EPT_AD_ENABLE_BIT);
+
+ /*
+ * If the (L2) guest does a vmfunc to the currently
+ * active ept pointer, we don't have to do anything else
+ */
+ if (vmcs12->ept_pointer != address) {
+ if (!valid_ept_address(vcpu, address)) {
+ kunmap(page);
+ nested_release_page_clean(page);
+ return 1;
+ }
+ kvm_mmu_unload(vcpu);
+ mmu->ept_ad = accessed_dirty;
+ mmu->base_role.ad_disabled = !accessed_dirty;
+ vmcs12->ept_pointer = address;
+ /*
+ * TODO: Check what's the correct approach in case
+ * mmu reload fails. Currently, we just let the next
+ * reload potentially fail
+ */
+ kvm_mmu_reload(vcpu);
+ }
+
+ kunmap(page);
+ nested_release_page_clean(page);
+ return 0;
+}
+
static int handle_vmfunc(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -7839,7 +7941,16 @@ static int handle_vmfunc(struct kvm_vcpu *vcpu)
vmcs12 = get_vmcs12(vcpu);
if ((vmcs12->vm_function_control & (1 << function)) == 0)
goto fail;
- WARN_ONCE(1, "VMCS12 VM function control should have been zero");
+
+ switch (function) {
+ case 0:
+ if (nested_vmx_eptp_switching(vcpu, vmcs12))
+ goto fail;
+ break;
+ default:
+ goto fail;
+ }
+ return kvm_skip_emulated_instruction(vcpu);
fail:
nested_vmx_vmexit(vcpu, vmx->exit_reason,
@@ -10437,10 +10548,17 @@ static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
vmx->nested.nested_vmx_entry_ctls_high))
return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
- if (nested_cpu_has_vmfunc(vmcs12) &&
- (vmcs12->vm_function_control &
- ~vmx->nested.nested_vmx_vmfunc_controls))
- return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
+ if (nested_cpu_has_vmfunc(vmcs12)) {
+ if (vmcs12->vm_function_control &
+ ~vmx->nested.nested_vmx_vmfunc_controls)
+ return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
+
+ if (nested_cpu_has_eptp_switching(vmcs12)) {
+ if (!nested_cpu_has_ept(vmcs12) ||
+ !page_address_valid(vcpu, vmcs12->eptp_list_address))
+ return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
+ }
+ }
if (vmcs12->cr3_target_count > nested_cpu_vmx_misc_cr3_count(vcpu))
return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
--
2.9.4
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH 3/3] KVM: nVMX: Emulate EPTP switching for the L1 hypervisor
2017-08-01 23:24 ` [PATCH 3/3] KVM: nVMX: Emulate EPTP switching " Bandan Das
@ 2017-08-03 11:39 ` David Hildenbrand
2017-08-03 12:41 ` Paolo Bonzini
0 siblings, 1 reply; 8+ messages in thread
From: David Hildenbrand @ 2017-08-03 11:39 UTC (permalink / raw)
To: Bandan Das, kvm; +Cc: pbonzini, rkrcmar, jmattson, linux-kernel
>
> +static bool valid_ept_address(struct kvm_vcpu *vcpu, u64 address)
> +{
> + struct vcpu_vmx *vmx = to_vmx(vcpu);
> + u64 mask = address & 0x7;
> + int maxphyaddr = cpuid_maxphyaddr(vcpu);
> +
> + /* Check for memory type validity */
> + switch (mask) {
> + case 0:
> + if (!(vmx->nested.nested_vmx_ept_caps & VMX_EPTP_UC_BIT))
> + return false;
> + break;
> + case 6:
> + if (!(vmx->nested.nested_vmx_ept_caps & VMX_EPTP_WB_BIT))
> + return false;
> + break;
> + default:
> + return false;
> + }
> +
> + /* Bits 5:3 must be 3 */
> + if (((address >> VMX_EPT_GAW_EPTP_SHIFT) & 0x7) != VMX_EPT_DEFAULT_GAW)
> + return false;
> +
> + /* Reserved bits should not be set */
> + if (address >> maxphyaddr || ((address >> 7) & 0x1f))
> + return false;
> +
> + /* AD, if set, should be supported */
> + if ((address & VMX_EPT_AD_ENABLE_BIT)) {
> + if (!enable_ept_ad_bits)
> + return false;
In theory (I guess) we would have to check here if
(vmx->nested.nested_vmx_ept_caps & VMX_EPT_AD_BIT)
But I am no expert on this.
> + }
> +
> + return true;
> +}
> +
> +static int nested_vmx_eptp_switching(struct kvm_vcpu *vcpu,
> + struct vmcs12 *vmcs12)
> +{
> + u32 index = vcpu->arch.regs[VCPU_REGS_RCX];
> + u64 *l1_eptp_list, address;
> + struct page *page;
> + bool accessed_dirty;
> + struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
> +
> + if (!nested_cpu_has_eptp_switching(vmcs12) ||
> + !nested_cpu_has_ept(vmcs12))
> + return 1;
> +
> + if (index >= VMFUNC_EPTP_ENTRIES)
> + return 1;
> +
> + page = nested_get_page(vcpu, vmcs12->eptp_list_address);
> + if (!page)
> + return 1;
> +
> + l1_eptp_list = kmap(page);
> + address = l1_eptp_list[index];
> + accessed_dirty = !!(address & VMX_EPT_AD_ENABLE_BIT);
Minor nit: Can't you directly do
kunmap(page);
nested_release_page_clean(page);
at this point?
We can fix this up later.
We could even later factor this out into sth. like "nested_vmx_read_guest".
--
Thanks,
David
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 3/3] KVM: nVMX: Emulate EPTP switching for the L1 hypervisor
2017-08-03 11:39 ` David Hildenbrand
@ 2017-08-03 12:41 ` Paolo Bonzini
2017-08-03 12:47 ` David Hildenbrand
2017-08-03 19:55 ` Bandan Das
0 siblings, 2 replies; 8+ messages in thread
From: Paolo Bonzini @ 2017-08-03 12:41 UTC (permalink / raw)
To: David Hildenbrand, Bandan Das, kvm; +Cc: rkrcmar, jmattson, linux-kernel
On 03/08/2017 13:39, David Hildenbrand wrote:
>> + /* AD, if set, should be supported */
>> + if ((address & VMX_EPT_AD_ENABLE_BIT)) {
>> + if (!enable_ept_ad_bits)
>> + return false;
> In theory (I guess) we would have to check here if
> (vmx->nested.nested_vmx_ept_caps & VMX_EPT_AD_BIT)
Yes, that's a more correct check than enable_ept_ad_bits.
>>
>> + page = nested_get_page(vcpu, vmcs12->eptp_list_address);
>> + if (!page)
>> + return 1;
>> +
>> + l1_eptp_list = kmap(page);
>> + address = l1_eptp_list[index];
>> + accessed_dirty = !!(address & VMX_EPT_AD_ENABLE_BIT);
>
> Minor nit: Can't you directly do
>
> kunmap(page);
> nested_release_page_clean(page);
>
> at this point?
>
> We can fix this up later.
You actually can do simply kvm_vcpu_read_guest_page(vcpu,
vmcs12->eptp_list_address >> PAGE_SHIFT, &address, index * 8, 8).
Paolo
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 3/3] KVM: nVMX: Emulate EPTP switching for the L1 hypervisor
2017-08-03 12:41 ` Paolo Bonzini
@ 2017-08-03 12:47 ` David Hildenbrand
2017-08-03 19:55 ` Bandan Das
1 sibling, 0 replies; 8+ messages in thread
From: David Hildenbrand @ 2017-08-03 12:47 UTC (permalink / raw)
To: Paolo Bonzini, Bandan Das, kvm; +Cc: rkrcmar, jmattson, linux-kernel
>> Minor nit: Can't you directly do
>>
>> kunmap(page);
>> nested_release_page_clean(page);
>>
>> at this point?
>>
>> We can fix this up later.
>
> You actually can do simply kvm_vcpu_read_guest_page(vcpu,
> vmcs12->eptp_list_address >> PAGE_SHIFT, &address, index * 8, 8).
>
Fascinating how nested is able to confuse me every time :) . Sure, this
is just a G1 address, not a G2 address ... (maybe we should rename
nested_get_page to guest_get_page ...)
> Paolo
>
--
Thanks,
David
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] KVM: nVMX: Emulate EPTP switching for the L1 hypervisor
2017-08-03 12:41 ` Paolo Bonzini
2017-08-03 12:47 ` David Hildenbrand
@ 2017-08-03 19:55 ` Bandan Das
1 sibling, 0 replies; 8+ messages in thread
From: Bandan Das @ 2017-08-03 19:55 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: David Hildenbrand, kvm, rkrcmar, jmattson, linux-kernel
Paolo Bonzini <pbonzini@redhat.com> writes:
> On 03/08/2017 13:39, David Hildenbrand wrote:
>>> + /* AD, if set, should be supported */
>>> + if ((address & VMX_EPT_AD_ENABLE_BIT)) {
>>> + if (!enable_ept_ad_bits)
>>> + return false;
>> In theory (I guess) we would have to check here if
>> (vmx->nested.nested_vmx_ept_caps & VMX_EPT_AD_BIT)
>
> Yes, that's a more correct check than enable_ept_ad_bits.
>
>>>
>>> + page = nested_get_page(vcpu, vmcs12->eptp_list_address);
>>> + if (!page)
>>> + return 1;
>>> +
>>> + l1_eptp_list = kmap(page);
>>> + address = l1_eptp_list[index];
>>> + accessed_dirty = !!(address & VMX_EPT_AD_ENABLE_BIT);
>>
>> Minor nit: Can't you directly do
>>
>> kunmap(page);
>> nested_release_page_clean(page);
>>
>> at this point?
>>
>> We can fix this up later.
>
> You actually can do simply kvm_vcpu_read_guest_page(vcpu,
> vmcs12->eptp_list_address >> PAGE_SHIFT, &address, index * 8, 8).
Thanks Paolo, for the interesting tip. David, I sent a new version with the correct
check for AD and using this instead of kmap(page).
> Paolo
^ permalink raw reply [flat|nested] 8+ messages in thread