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