[RFC PATCH part-5 10/22] pkvm: x86: Add has_vmcs_field() API for physical vmx capability check

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Tina Zhang <tina.zhang@xxxxxxxxx>

Some fields in vmcs exist only on processors that support the 1-setting
of those fields in the control registers [1]. VMREAD/VMWRITE from/to
unsupported VMCS component leads to VMfailValid [2].

Introduce a function called has_vmcs_field() which can be used to check
if a field exists in vmcs before using VMREAD/VMWRITE to access the field.

[1]: SDM: Appendix B Field Encoding in VMCS, NOTES.
[2]: SDM: VMX Instruction Reference chapter, VMWRITE/VMREAD.

Signed-off-by: Tina Zhang <tina.zhang@xxxxxxxxx>
Signed-off-by: Chuanxiao Dong <chuanxiao.dong@xxxxxxxxx>
Signed-off-by: Jason Chen CJ <jason.cj.chen@xxxxxxxxx>
---
 arch/x86/kvm/vmx/pkvm/hyp/nested.c | 115 +++++++++++++++++++++++++++++
 arch/x86/kvm/vmx/pkvm/pkvm_host.c  |  29 ++++++++
 2 files changed, 144 insertions(+)

diff --git a/arch/x86/kvm/vmx/pkvm/hyp/nested.c b/arch/x86/kvm/vmx/pkvm/hyp/nested.c
index f5e2eb8f51c8..31ad33f2cdbf 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/nested.c
+++ b/arch/x86/kvm/vmx/pkvm/hyp/nested.c
@@ -8,6 +8,121 @@
 #include "pkvm_hyp.h"
 #include "debug.h"
 
+/**
+ * According to SDM Appendix B Field Encoding in VMCS, some fields only
+ * exist on processor that support the 1-setting of the corresponding
+ * fields in the control regs.
+ */
+static bool has_vmcs_field(u16 encoding)
+{
+	struct nested_vmx_msrs *msrs = &pkvm_hyp->vmcs_config.nested;
+
+	switch (encoding) {
+	case MSR_BITMAP:
+		return msrs->procbased_ctls_high & CPU_BASED_USE_MSR_BITMAPS;
+	case VIRTUAL_APIC_PAGE_ADDR:
+	case VIRTUAL_APIC_PAGE_ADDR_HIGH:
+	case TPR_THRESHOLD:
+		return msrs->procbased_ctls_high & CPU_BASED_TPR_SHADOW;
+	case SECONDARY_VM_EXEC_CONTROL:
+		return msrs->procbased_ctls_high &
+			CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
+
+	case VIRTUAL_PROCESSOR_ID:
+		return msrs->secondary_ctls_high & SECONDARY_EXEC_ENABLE_VPID;
+	case XSS_EXIT_BITMAP:
+		return msrs->secondary_ctls_high & SECONDARY_EXEC_XSAVES;
+	case PML_ADDRESS:
+		return msrs->secondary_ctls_high & SECONDARY_EXEC_ENABLE_PML;
+	case VM_FUNCTION_CONTROL:
+		return msrs->secondary_ctls_high & SECONDARY_EXEC_ENABLE_VMFUNC;
+	case EPT_POINTER:
+		return msrs->secondary_ctls_high & SECONDARY_EXEC_ENABLE_EPT;
+	case EOI_EXIT_BITMAP0:
+	case EOI_EXIT_BITMAP1:
+	case EOI_EXIT_BITMAP2:
+	case EOI_EXIT_BITMAP3:
+		return msrs->secondary_ctls_high &
+			SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY;
+	case VMREAD_BITMAP:
+	case VMWRITE_BITMAP:
+		return msrs->secondary_ctls_high & SECONDARY_EXEC_SHADOW_VMCS;
+	case ENCLS_EXITING_BITMAP:
+		return msrs->secondary_ctls_high &
+			SECONDARY_EXEC_ENCLS_EXITING;
+	case GUEST_INTR_STATUS:
+		return msrs->secondary_ctls_high &
+			SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY;
+	case GUEST_PML_INDEX:
+		return msrs->secondary_ctls_high & SECONDARY_EXEC_ENABLE_PML;
+	case APIC_ACCESS_ADDR:
+	case APIC_ACCESS_ADDR_HIGH:
+		return msrs->secondary_ctls_high &
+			SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+	case TSC_MULTIPLIER:
+	case TSC_MULTIPLIER_HIGH:
+		return msrs->secondary_ctls_high &
+			SECONDARY_EXEC_TSC_SCALING;
+	case GUEST_PHYSICAL_ADDRESS:
+	case GUEST_PHYSICAL_ADDRESS_HIGH:
+		return msrs->secondary_ctls_high &
+			SECONDARY_EXEC_ENABLE_EPT;
+	case GUEST_PDPTR0:
+	case GUEST_PDPTR0_HIGH:
+	case GUEST_PDPTR1:
+	case GUEST_PDPTR1_HIGH:
+	case GUEST_PDPTR2:
+	case GUEST_PDPTR2_HIGH:
+	case GUEST_PDPTR3:
+	case GUEST_PDPTR3_HIGH:
+		return msrs->secondary_ctls_high & SECONDARY_EXEC_ENABLE_EPT;
+	case PLE_GAP:
+	case PLE_WINDOW:
+		return msrs->secondary_ctls_high &
+			SECONDARY_EXEC_PAUSE_LOOP_EXITING;
+
+	case VMX_PREEMPTION_TIMER_VALUE:
+		return msrs->pinbased_ctls_high &
+			PIN_BASED_VMX_PREEMPTION_TIMER;
+	case POSTED_INTR_DESC_ADDR:
+		return msrs->pinbased_ctls_high & PIN_BASED_POSTED_INTR;
+	case POSTED_INTR_NV:
+		return msrs->pinbased_ctls_high & PIN_BASED_POSTED_INTR;
+	case GUEST_IA32_PAT:
+	case GUEST_IA32_PAT_HIGH:
+		return (msrs->entry_ctls_high & VM_ENTRY_LOAD_IA32_PAT) ||
+			(msrs->exit_ctls_high & VM_EXIT_SAVE_IA32_PAT);
+	case GUEST_IA32_EFER:
+	case GUEST_IA32_EFER_HIGH:
+		return (msrs->entry_ctls_high & VM_ENTRY_LOAD_IA32_EFER) ||
+			(msrs->exit_ctls_high & VM_EXIT_SAVE_IA32_EFER);
+	case GUEST_IA32_PERF_GLOBAL_CTRL:
+	case GUEST_IA32_PERF_GLOBAL_CTRL_HIGH:
+		return msrs->entry_ctls_high & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
+	case GUEST_BNDCFGS:
+	case GUEST_BNDCFGS_HIGH:
+		return (msrs->entry_ctls_high & VM_ENTRY_LOAD_BNDCFGS) ||
+			(msrs->exit_ctls_high & VM_EXIT_CLEAR_BNDCFGS);
+	case GUEST_IA32_RTIT_CTL:
+	case GUEST_IA32_RTIT_CTL_HIGH:
+		return (msrs->entry_ctls_high & VM_ENTRY_LOAD_IA32_RTIT_CTL) ||
+			(msrs->exit_ctls_high & VM_EXIT_CLEAR_IA32_RTIT_CTL);
+	case HOST_IA32_PAT:
+	case HOST_IA32_PAT_HIGH:
+		return msrs->exit_ctls_high & VM_EXIT_LOAD_IA32_PAT;
+	case HOST_IA32_EFER:
+	case HOST_IA32_EFER_HIGH:
+		return msrs->exit_ctls_high & VM_EXIT_LOAD_IA32_EFER;
+	case HOST_IA32_PERF_GLOBAL_CTRL:
+	case HOST_IA32_PERF_GLOBAL_CTRL_HIGH:
+		return msrs->exit_ctls_high & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
+	case EPTP_LIST_ADDRESS:
+		return msrs->vmfunc_controls & VMX_VMFUNC_EPTP_SWITCHING;
+	default:
+		return true;
+	}
+}
+
 enum VMXResult {
 	VMsucceed,
 	VMfailValid,
diff --git a/arch/x86/kvm/vmx/pkvm/pkvm_host.c b/arch/x86/kvm/vmx/pkvm/pkvm_host.c
index 2dff1123b61f..4ea82a147af5 100644
--- a/arch/x86/kvm/vmx/pkvm/pkvm_host.c
+++ b/arch/x86/kvm/vmx/pkvm/pkvm_host.c
@@ -426,6 +426,33 @@ static __init void pkvm_host_deinit_vmx(struct pkvm_host_vcpu *vcpu)
 		vmx->vmcs01.msr_bitmap = NULL;
 }
 
+static __init void pkvm_host_setup_nested_vmx_cap(struct pkvm_hyp *pkvm)
+{
+	struct nested_vmx_msrs *msrs = &pkvm->vmcs_config.nested;
+
+	rdmsr(MSR_IA32_VMX_PROCBASED_CTLS,
+		msrs->procbased_ctls_low,
+		msrs->procbased_ctls_high);
+
+	rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS2,
+			&msrs->secondary_ctls_low,
+			&msrs->secondary_ctls_high);
+
+	rdmsr(MSR_IA32_VMX_PINBASED_CTLS,
+		msrs->pinbased_ctls_low,
+		msrs->pinbased_ctls_high);
+
+	rdmsrl_safe(MSR_IA32_VMX_VMFUNC, &msrs->vmfunc_controls);
+
+	rdmsr(MSR_IA32_VMX_EXIT_CTLS,
+		msrs->exit_ctls_low,
+		msrs->exit_ctls_high);
+
+	rdmsr(MSR_IA32_VMX_ENTRY_CTLS,
+		msrs->entry_ctls_low,
+		msrs->entry_ctls_high);
+}
+
 static __init int pkvm_host_check_and_setup_vmx_cap(struct pkvm_hyp *pkvm)
 {
 	struct vmcs_config *vmcs_config = &pkvm->vmcs_config;
@@ -476,6 +503,8 @@ static __init int pkvm_host_check_and_setup_vmx_cap(struct pkvm_hyp *pkvm)
 		pr_info("vmentry_ctrl 0x%x\n", vmcs_config->vmentry_ctrl);
 	}
 
+	pkvm_host_setup_nested_vmx_cap(pkvm);
+
 	return ret;
 }
 
-- 
2.25.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux