KVM: VMX: Support updated eVMCSv1 revision + use vmcs_config for L1 VMX MSRs
Vitaly Kuznetsov
maintainerv6 cover KVM: VMX: Support updated eVMCSv1 revision + use vmcs_config for L1 VMX MSRs
Changes since "[RFC PATCH v6 00/36] KVM: x86: eVMCS rework":
- Drop the most controversial TSC_SCALING enablement for Hyper-V on KVM:
- "KVM: nVMX: Enforce unsupported eVMCS in VMX MSRs for host accesses" patch dropped.
- "KVM: nVMX: Support TSC scaling with enlightened VMCS" patch dropped.
- "KVM: selftests: Enable TSC scaling in evmcs selftest" patch dropped.
Original description:
Enlightened VMCS v1 definition was updates to include fields for the following features:
- PerfGlobalCtrl
- EnclsExitingBitmap
- TSC scaling
- GuestLbrCtl
- CET
- SSP
While the information is missing in the publicly available TLFS, the updated definition comes with a new feature bit in CPUID.0x4000000A.EBX (BIT 0) for PerfGlobalCtrl.
Add support for the new revision to KVM. SSP, CET and GuestLbrCtl features are not currently supported by KVM. Note: for Hyper-V on KVM, only PerfGlobalCtrl is added as it has a dedicated CPUID bit. The way how to enable different layouts of eVMSC in a VMM friendly way is still under discussion.
While on it, implement Sean's idea to use vmcs_config for setting up L1 VMX control MSRs instead of re-reading host MSRs.
Jim Mattson (1):
KVM: x86: VMX: Replace some Intel model numbers with mnemonics
Sean Christopherson (9):
KVM: x86: Check for existing Hyper-V vCPU in kvm_hv_vcpu_init()
KVM: x86: Report error when setting CPUID if Hyper-V allocation fails
KVM: nVMX: Treat eVMCS as enabled for guest iff Hyper-V is also
enabled
KVM: nVMX: Use CC() macro to handle eVMCS unsupported controls checks
KVM: nVMX: WARN once and fail VM-Enter if eVMCS sees VMFUNC[63:32] !=
0
KVM: nVMX: Don't propagate vmcs12's PERF_GLOBAL_CTRL settings to
vmcs02 KVM: nVMX: Always emulate PERF_GLOBAL_CTRL VM-Entry/VM-Exit controls
KVM: VMX: Don't toggle VM_ENTRY_IA32E_MODE for 32-bit kernels/KVM
KVM: VMX: Adjust CR3/INVPLG interception for EPT=y at runtime, not
setup
Vitaly Kuznetsov (23):
x86/hyperv: Fix 'struct hv_enlightened_vmcs' definition x86/hyperv: Update 'struct hv_enlightened_vmcs' definition
KVM: x86: Zero out entire Hyper-V CPUID cache before processing
entries
KVM: nVMX: Refactor unsupported eVMCS controls logic to use 2-d array
KVM: VMX: Define VMCS-to-EVMCS conversion for the new fields
KVM: nVMX: Support several new fields in eVMCSv1
KVM: x86: hyper-v: Cache HYPERV_CPUID_NESTED_FEATURES CPUID leaf
KVM: selftests: Add ENCLS_EXITING_BITMAP{,HIGH} VMCS fields
KVM: selftests: Switch to updated eVMCSv1 definition
KVM: nVMX: Support PERF_GLOBAL_CTRL with enlightened VMCS
KVM: VMX: Get rid of eVMCS specific VMX controls sanitization
KVM: VMX: Check VM_ENTRY_IA32E_MODE in setup_vmcs_config()
KVM: VMX: Check CPU_BASED_{INTR,NMI}_WINDOW_EXITING in
setup_vmcs_config()
KVM: VMX: Tweak the special handling of SECONDARY_EXEC_ENCLS_EXITING
in setup_vmcs_config()
KVM: VMX: Extend VMX controls macro shenanigans
KVM: VMX: Move CPU_BASED_CR8_{LOAD,STORE}_EXITING filtering out of
setup_vmcs_config()
KVM: VMX: Add missing VMEXIT controls to vmcs_config
KVM: VMX: Add missing CPU based VM execution controls to vmcs_config
KVM: VMX: Move LOAD_IA32_PERF_GLOBAL_CTRL errata handling out of
setup_vmcs_config()
KVM: nVMX: Always set required-1 bits of pinbased_ctls to
PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR
KVM: nVMX: Use sanitized allowed-1 bits for VMX control MSRs
KVM: VMX: Cache MSR_IA32_VMX_MISC in vmcs_config
KVM: nVMX: Use cached host MSR_IA32_VMX_MISC value for setting up
nested MSR
arch/x86/include/asm/hyperv-tlfs.h | 22 +- arch/x86/include/asm/kvm_host.h | 2 + arch/x86/kvm/cpuid.c | 18 +- arch/x86/kvm/hyperv.c | 70 +++-- arch/x86/kvm/hyperv.h | 6 +- arch/x86/kvm/vmx/capabilities.h | 14 +- arch/x86/kvm/vmx/evmcs.c | 192 ++++++++----- arch/x86/kvm/vmx/evmcs.h | 10 +- arch/x86/kvm/vmx/nested.c | 94 ++++--- arch/x86/kvm/vmx/nested.h | 2 +- arch/x86/kvm/vmx/vmx.c | 259 ++++++++---------- arch/x86/kvm/vmx/vmx.h | 172 ++++++++++-- .../selftests/kvm/include/x86_64/evmcs.h | 45 ++- .../selftests/kvm/include/x86_64/vmx.h | 2 + 14 files changed, 584 insertions(+), 324 deletions(-)
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 1/33 x86/hyperv: Fix 'struct hv_enlightened_vmcs' definition
Section 1.9 of TLFS v6.0b says:
"All structures are padded in such a way that fields are aligned naturally (that is, an 8-byte field is aligned to an offset of 8 bytes and so on)".
'struct enlightened_vmcs' has a glitch:
...
struct {
u32 nested_flush_hypercall:1; /* 836: 0 4 */
u32 msr_bitmap:1; /* 836: 1 4 */
u32 reserved:30; /* 836: 2 4 */
} hv_enlightenments_control; /* 836 4 */
u32 hv_vp_id; /* 840 4 */
u64 hv_vm_id; /* 844 8 */
u64 partition_assist_page; /* 852 8 */...
And the observed values in 'partition_assist_page' make no sense at all. Fix the layout by padding the structure properly.
--- arch/x86/include/asm/hyperv-tlfs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/include/asm/hyperv-tlfs.h +2 -2
@@ -546,7 +546,7 @@ struct hv_enlightened_vmcs {u64 guest_rip;u32 hv_clean_fields; -u32 hv_padding_32; +u32 padding32_1;u32 hv_synthetic_controls;struct {u32 nested_flush_hypercall:1 ;
@@ -554,7 +554,7 @@ struct hv_enlightened_vmcs { u32 reserved:30; }__packed hv_enlightenments_control;u32 hv_vp_id; - +u32 padding32_2;u64 hv_vm_id;u64 partition_assist_page;u64 padding64_4[4 ];
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 2/33 x86/hyperv: Update 'struct hv_enlightened_vmcs' definition
In reply to Vitaly KuznetsovUpdated Hyper-V Enlightened VMCS specification lists several new fields for the following features:
- PerfGlobalCtrl
- EnclsExitingBitmap
- Tsc Scaling
- GuestLbrCtl
- CET
- SSP
Update the definition.
Note, the updated spec also provides an additional CPUID feature flag, CPUIDD.0x4000000A.EBX BIT(0), for PerfGlobalCtrl to workaround a Windows 11 quirk. Despite what the TLFS says:
Indicates support for the GuestPerfGlobalCtrl and HostPerfGlobalCtrl fields in the enlightened VMCS.
guests can safely use the fields if they are enumerated in the architectural VMX MSRs. I.e. KVM-on-HyperV doesn't need to check the CPUID bit, but KVM-as-HyperV must ensure the bit is set if PerfGlobalCtrl fields are exposed to L1.
https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs
--- arch/x86/include/asm/hyperv-tlfs.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
arch/x86/include/asm/hyperv-tlfs.h +16 -2
@@ -138,6 +138,9 @@#define HV_X64_NESTED_GUEST_MAPPING_FLUSH BIT(18)#define HV_X64_NESTED_MSR_BITMAP BIT(19) +/* Nested features #2. These are HYPERV_CPUID_NESTED_FEATURES.EBX bits. */ +#define HV_X64_NESTED_EVMCS1_PERF_GLOBAL_CTRL BIT(0) +/* * This is specific to AMD and specifies that enlightened TLB flush is * supported. If guest opts in to this feature, ASID invalidations only
@@ -559,9 +562,20 @@ struct hv_enlightened_vmcs {u64 partition_assist_page;u64 padding64_4[4 ];u64 guest_bndcfgs; -u64 padding64_5[7 ]; +u64 guest_ia32_perf_global_ctrl; +u64 guest_ia32_s_cet; +u64 guest_ssp; +u64 guest_ia32_int_ssp_table_addr; +u64 guest_ia32_lbr_ctl; +u64 padding64_5[2 ];u64 xss_exit_bitmap; -u64 padding64_6[7 ]; +u64 encls_exiting_bitmap; +u64 host_ia32_perf_global_ctrl; +u64 tsc_multiplier; +u64 host_ia32_s_cet; +u64 host_ssp; +u64 host_ia32_int_ssp_table_addr; +u64 padding64_6; } __packed;#define HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE 0
Signature · 1 line
2.37.2
Re: [PATCH v6 02/33] x86/hyperv: Update 'struct hv_enlightened_vmcs' definition
Quoted 24 lines · Vitaly Kuznetsov
Updated Hyper-V Enlightened VMCS specification lists several new fields for the following features:
- PerfGlobalCtrl
- EnclsExitingBitmap
- Tsc Scaling
- GuestLbrCtl
- CET
- SSPUpdate the definition.
Note, the updated spec also provides an additional CPUID feature flag, CPUIDD.0x4000000A.EBX BIT(0), for PerfGlobalCtrl to workaround a Windows 11 quirk. Despite what the TLFS says:
Indicates support for the GuestPerfGlobalCtrl and HostPerfGlobalCtrl fields in the enlightened VMCS.
guests can safely use the fields if they are enumerated in the architectural VMX MSRs. I.e. KVM-on-HyperV doesn't need to check the CPUID bit, but KVM-as-HyperV must ensure the bit is set if PerfGlobalCtrl fields are exposed to L1.
Quoted 5 lines
https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs
Signed-off-by Vitaly Kuznetsov <[email protected]>[sean: tweak CPUID name to make it PerfGlobalCtrl only]Signed-off-by Sean Christopherson <[email protected]>
Vitaly Kuznetsov
maintainerPATCH v6 3/33 KVM: x86: Zero out entire Hyper-V CPUID cache before processing entries
In reply to Vitaly KuznetsovWipe the whole 'hv_vcpu->cpuid_cache' with memset() instead of having to zero each particular member when the corresponding CPUID entry was not found.
No functional change intended.
--- arch/x86/kvm/hyperv.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-)
arch/x86/kvm/hyperv.c +2 -9
@@ -2005,31 +2005,24 @@ void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu) hv_vcpu =to_hv_vcpu (vcpu); +memset (&hv_vcpu->cpuid_cache,0 ,sizeof (hv_vcpu->cpuid_cache)); + entry =kvm_find_cpuid_entry (vcpu,HYPERV_CPUID_FEATURES );if (entry) { hv_vcpu->cpuid_cache.features_eax = entry->eax; hv_vcpu->cpuid_cache.features_ebx = entry->ebx; hv_vcpu->cpuid_cache.features_edx = entry->edx; - }else { - hv_vcpu->cpuid_cache.features_eax =0 ; - hv_vcpu->cpuid_cache.features_ebx =0 ; - hv_vcpu->cpuid_cache.features_edx =0 ; } entry =kvm_find_cpuid_entry (vcpu,HYPERV_CPUID_ENLIGHTMENT_INFO );if (entry) { hv_vcpu->cpuid_cache.enlightenments_eax = entry->eax; hv_vcpu->cpuid_cache.enlightenments_ebx = entry->ebx; - }else { - hv_vcpu->cpuid_cache.enlightenments_eax =0 ; - hv_vcpu->cpuid_cache.enlightenments_ebx =0 ; } entry =kvm_find_cpuid_entry (vcpu,HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES );if (entry) hv_vcpu->cpuid_cache.syndbg_cap_eax = entry->eax; -else - hv_vcpu->cpuid_cache.syndbg_cap_eax =0 ; }int kvm_hv_set_enforce_cpuid (struct kvm_vcpu *vcpu,bool enforce)
Signature · 1 line
2.37.2
Re: [PATCH v6 03/33] KVM: x86: Zero out entire Hyper-V CPUID cache before processing entries
Quoted 9 lines · Vitaly Kuznetsov
Wipe the whole '
hv_vcpu->cpuid_cache' withmemset()instead of having to zero each particular member when the corresponding CPUID entry was not found.No functional change intended.
Signed-off-by Vitaly Kuznetsov <[email protected]>[sean: split to separate patch]Signed-off-by Sean Christopherson <[email protected]>
Vitaly Kuznetsov
maintainerPATCH v6 4/33 KVM: x86: Check for existing Hyper-V vCPU in kvm_hv_vcpu_init()
In reply to Vitaly KuznetsovFrom: Sean Christopherson <[email protected]>
When potentially allocating/initializing the Hyper-V vCPU struct, check for an existing instance in kvm_hv_vcpu_init() instead of requiring callers to perform the check. Relying on callers to do the check is risky as it's all too easy for KVM to overwrite vcpu->arch.hyperv and leak memory, and it adds additional burden on callers without much benefit.
No functional change intended.
--- arch/x86/kvm/hyperv.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-)
arch/x86/kvm/hyperv.c +12 -15
@@ -936,9 +936,12 @@ static void stimer_init(struct kvm_vcpu_hv_stimer *stimer, int timer_index)static int kvm_hv_vcpu_init (struct kvm_vcpu *vcpu) { -struct kvm_vcpu_hv *hv_vcpu; +struct kvm_vcpu_hv *hv_vcpu =to_hv_vcpu (vcpu);int i; +if (hv_vcpu) +return 0 ; + hv_vcpu =kzalloc (sizeof (struct kvm_vcpu_hv ),GFP_KERNEL_ACCOUNT );if (!hv_vcpu)return -ENOMEM ;
@@ -962,11 +965,9 @@ int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages)struct kvm_vcpu_hv_synic *synic;int r; -if (!to_hv_vcpu (vcpu)) { - r =kvm_hv_vcpu_init (vcpu); -if (r) -return r; - } + r =kvm_hv_vcpu_init (vcpu); +if (r) +return r; synic =to_hv_synic (vcpu);
@@ -1660,10 +1661,8 @@ int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)if (!host && !vcpu->arch.hyperv_enabled)return 1 ; -if (!to_hv_vcpu (vcpu)) { -if (kvm_hv_vcpu_init (vcpu)) -return 1 ; - } +if (kvm_hv_vcpu_init (vcpu)) +return 1 ;if (kvm_hv_msr_partition_wide (msr)) {int r;
@@ -1683,10 +1682,8 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host)if (!host && !vcpu->arch.hyperv_enabled)return 1 ; -if (!to_hv_vcpu (vcpu)) { -if (kvm_hv_vcpu_init (vcpu)) -return 1 ; - } +if (kvm_hv_vcpu_init (vcpu)) +return 1 ;if (kvm_hv_msr_partition_wide (msr)) {int r;
@@ -2000,7 +1997,7 @@ void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu)return ; } -if (!to_hv_vcpu (vcpu) &&kvm_hv_vcpu_init (vcpu)) +if (kvm_hv_vcpu_init (vcpu))return ; hv_vcpu =to_hv_vcpu (vcpu);
Signature · 1 line
2.37.2
Re: [PATCH v6 04/33] KVM: x86: Check for existing Hyper-V vCPU in kvm_hv_vcpu_init()
Quoted 9 lines · Vitaly Kuznetsov
From: Sean Christopherson <[email protected]>
When potentially allocating/initializing the Hyper-V vCPU struct, check for an existing instance in
kvm_hv_vcpu_init()instead of requiring callers to perform the check. Relying on callers to do the check is risky as it's all too easy for KVM to overwritevcpu->arch.hypervand leak memory, and it adds additional burden on callers without much benefit.
Quoted 4 lines
No functional change intended.
Signed-off-by Sean Christopherson <[email protected]>Signed-off-by Vitaly Kuznetsov <[email protected]>
Vitaly Kuznetsov
maintainerPATCH v6 5/33 KVM: x86: Report error when setting CPUID if Hyper-V allocation fails
In reply to Vitaly KuznetsovFrom: Sean Christopherson <[email protected]>
Return -ENOMEM back to userspace if allocating the Hyper-V vCPU struct fails when enabling Hyper-V in guest CPUID. Silently ignoring failure means that KVM will not have an up-to-date CPUID cache if allocating the struct succeeds later on, e.g. when activating SynIC.
Rejecting the CPUID operation also guarantess that vcpu->arch.hyperv is non-NULL if hyperv_enabled is true, which will allow for additional cleanup, e.g. in the eVMCS code.
Note, the initialization needs to be done before CPUID is set, and more subtly before kvm_check_cpuid(), which potentially enables dynamic XFEATURES. Sadly, there's no easy way to avoid exposing Hyper-V details to CPUID or vice versa. Expose kvm_hv_vcpu_init() and the Hyper-V CPUID signature to CPUID instead of exposing cpuid_entry2_find() outside of CPUID code. It's hard to envision kvm_hv_vcpu_init() being misused, whereas cpuid_entry2_find() absolutely shouldn't be used outside of core CPUID code.
--- arch/x86/kvm/cpuid.c | 18 +++++++++++++++++- arch/x86/kvm/hyperv.c | 30 ++++++++++++++---------------- arch/x86/kvm/hyperv.h | 6 +++++- 3 files changed, 36 insertions(+), 18 deletions(-)
arch/x86/kvm/cpuid.c +17 -1
@@ -311,6 +311,15 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) }EXPORT_SYMBOL_GPL (kvm_update_cpuid_runtime); +static bool kvm_cpuid_has_hyperv (struct kvm_cpuid_entry2 *entries,int nent) +{ +struct kvm_cpuid_entry2 *entry; + + entry =cpuid_entry2_find (entries, nent,HYPERV_CPUID_INTERFACE , +KVM_CPUID_INDEX_NOT_SIGNIFICANT ); +return entry && entry->eax ==HYPERV_CPUID_SIGNATURE_EAX ; +} +static void kvm_vcpu_after_set_cpuid (struct kvm_vcpu *vcpu) {struct kvm_lapic *apic = vcpu->arch.apic;
@@ -341,7 +350,8 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) vcpu->arch.cr4_guest_rsvd_bits =__cr4_reserved_bits (guest_cpuid_has, vcpu); -kvm_hv_set_cpuid (vcpu); +kvm_hv_set_cpuid (vcpu,kvm_cpuid_has_hyperv (vcpu->arch.cpuid_entries, + vcpu->arch.cpuid_nent));/* Invoke the vendor callback only after the above state is updated. */ static_call (kvm_x86_vcpu_after_set_cpuid)(vcpu);
@@ -404,6 +414,12 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,return 0 ; } +if (kvm_cpuid_has_hyperv (e2, nent)) { + r =kvm_hv_vcpu_init (vcpu); +if (r) +return r; + } + r =kvm_check_cpuid (vcpu, e2, nent);if (r)return r;
arch/x86/kvm/hyperv.c +14 -16
@@ -38,9 +38,6 @@#include "irq.h" #include "fpu.h" -/* "Hv#1" signature */ -#define HYPERV_CPUID_SIGNATURE_EAX 0x31237648 -#define KVM_HV_MAX_SPARSE_VCPU_SET_BITS DIV_ROUND_UP(KVM_MAX_VCPUS, 64) static void stimer_mark_pending(struct kvm_vcpu_hv_stimer *stimer,
@@ -934,7 +931,7 @@ static void stimer_init(struct kvm_vcpu_hv_stimer *stimer, int timer_index)stimer_prepare_msg (stimer); } -static int kvm_hv_vcpu_init (struct kvm_vcpu *vcpu) +int kvm_hv_vcpu_init (struct kvm_vcpu *vcpu) {struct kvm_vcpu_hv *hv_vcpu =to_hv_vcpu (vcpu);int i;
@@ -1984,26 +1981,27 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)return HV_STATUS_SUCCESS ; } -void kvm_hv_set_cpuid (struct kvm_vcpu *vcpu) +void kvm_hv_set_cpuid (struct kvm_vcpu *vcpu,bool hyperv_enabled) { +struct kvm_vcpu_hv *hv_vcpu =to_hv_vcpu (vcpu);struct kvm_cpuid_entry2 *entry; -struct kvm_vcpu_hv *hv_vcpu; - entry =kvm_find_cpuid_entry (vcpu,HYPERV_CPUID_INTERFACE ); -if (entry && entry->eax ==HYPERV_CPUID_SIGNATURE_EAX ) { - vcpu->arch.hyperv_enabled = true; - }else { - vcpu->arch.hyperv_enabled = false; -return ; - } + vcpu->arch.hyperv_enabled = hyperv_enabled; -if (kvm_hv_vcpu_init (vcpu)) +if (!hv_vcpu) { +/* +* KVM should have already allocated kvm_vcpu_hv if Hyper-V is +* enabled in CPUID. +*/ +WARN_ON_ONCE (vcpu->arch.hyperv_enabled);return ; - - hv_vcpu =to_hv_vcpu (vcpu); + }memset (&hv_vcpu->cpuid_cache,0 ,sizeof (hv_vcpu->cpuid_cache)); +if (!vcpu->arch.hyperv_enabled) +return ; + entry =kvm_find_cpuid_entry (vcpu,HYPERV_CPUID_FEATURES );if (entry) { hv_vcpu->cpuid_cache.features_eax = entry->eax;
arch/x86/kvm/hyperv.h +5 -1
@@ -23,6 +23,9 @@#include <linux/kvm_host.h> +/* "Hv#1" signature */ +#define HYPERV_CPUID_SIGNATURE_EAX 0x31237648 +/* * The #defines related to the synthetic debugger are required by KDNet, but * they are not documented in the Hyper-V TLFS because the synthetic debugger
@@ -141,7 +144,8 @@ void kvm_hv_request_tsc_page_update(struct kvm *kvm);void kvm_hv_init_vm (struct kvm *kvm);void kvm_hv_destroy_vm (struct kvm *kvm); -void kvm_hv_set_cpuid (struct kvm_vcpu *vcpu); +int kvm_hv_vcpu_init (struct kvm_vcpu *vcpu); +void kvm_hv_set_cpuid (struct kvm_vcpu *vcpu,bool hyperv_enabled);int kvm_hv_set_enforce_cpuid (struct kvm_vcpu *vcpu,bool enforce);int kvm_vm_ioctl_hv_eventfd (struct kvm *kvm,struct kvm_hyperv_eventfd *args); int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 6/33 KVM: nVMX: Treat eVMCS as enabled for guest iff Hyper-V is also enabled
In reply to Vitaly KuznetsovFrom: Sean Christopherson <[email protected]>
When querying whether or not eVMCS is enabled on behalf of the guest, treat eVMCS as enable if and only if Hyper-V is enabled/exposed to the guest.
Note, flows that come from the host, e.g. KVM_SET_NESTED_STATE, must NOT check for Hyper-V being enabled as KVM doesn't require guest CPUID to be set before most ioctls().
--- arch/x86/kvm/vmx/evmcs.c | 3 +++ arch/x86/kvm/vmx/nested.c | 8 ++++---- arch/x86/kvm/vmx/vmx.c | 3 +-- arch/x86/kvm/vmx/vmx.h | 10 ++++++++++ 4 files changed, 18 insertions(+), 6 deletions(-)
arch/x86/kvm/vmx/evmcs.c +3 -0
@@ -334,6 +334,9 @@ uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu)* versions: lower 8 bits is the minimal version, higher 8 bits is the * maximum supported version. KVM supports versions from 1 to * KVM_EVMCS_VERSION. +* +* Note, do not check the Hyper-V is fully enabled in guest CPUID, this +* helper is used to _get_ the vCPU's supported CPUID. */ if (kvm_cpu_cap_get (X86_FEATURE_VMX ) && (!vcpu ||to_vmx (vcpu)->nested.enlightened_vmcs_enabled))
arch/x86/kvm/vmx/nested.c +4 -4
@@ -1982,7 +1982,7 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(bool evmcs_gpa_changed = false;u64 evmcs_gpa; -if (likely (!vmx->nested.enlightened_vmcs_enabled)) +if (likely (!guest_cpuid_has_evmcs (vcpu)))return EVMPTRLD_DISABLED ;if (!nested_enlightened_vmentry (vcpu, &evmcs_gpa)) {
@@ -2863,7 +2863,7 @@ static int nested_vmx_check_controls(struct kvm_vcpu *vcpu, nested_check_vm_entry_controls(vcpu, vmcs12))return -EINVAL ; -if (to_vmx (vcpu)->nested.enlightened_vmcs_enabled) +if (guest_cpuid_has_evmcs (vcpu))return nested_evmcs_check_controls (vmcs12);return 0 ;
@@ -3145,7 +3145,7 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)* L2 was running), map it here to make sure vmcs12 changes are * properly reflected. */ -if (vmx->nested.enlightened_vmcs_enabled && +if (guest_cpuid_has_evmcs (vcpu) && vmx->nested.hv_evmcs_vmptr ==EVMPTR_MAP_PENDING ) {enum nested_evmptrld_status evmptrld_status =nested_vmx_handle_enlightened_vmptrld (vcpu, false);
@@ -5067,7 +5067,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)* state. It is possible that the area will stay mapped as * vmx->nested.hv_evmcs but this shouldn't be a problem. */ -if (likely (!vmx->nested.enlightened_vmcs_enabled || +if (likely (!guest_cpuid_has_evmcs (vcpu) || !nested_enlightened_vmentry (vcpu, &evmcs_gpa))) {if (vmptr == vmx->nested.current_vmptr)nested_release_vmcs12 (vcpu);
arch/x86/kvm/vmx/vmx.c +1 -2
@@ -1930,8 +1930,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)* sanity checking and refuse to boot. Filter all unsupported * features out. */ -if (!msr_info->host_initiated && - vmx->nested.enlightened_vmcs_enabled) +if (!msr_info->host_initiated &&guest_cpuid_has_evmcs (vcpu))nested_evmcs_filter_control_msr (msr_info->index, &msr_info->data);break ;
arch/x86/kvm/vmx/vmx.h +10 -0
@@ -626,4 +626,14 @@ static inline bool vmx_can_use_ipiv(struct kvm_vcpu *vcpu) return lapic_in_kernel(vcpu) && enable_ipiv; } +static inline bool guest_cpuid_has_evmcs (struct kvm_vcpu *vcpu) +{ +/* +* eVMCS is exposed to the guest if Hyper-V is enabled in CPUID and +* eVMCS has been explicitly enabled by userspace. +*/ +return vcpu->arch.hyperv_enabled && +to_vmx (vcpu)->nested.enlightened_vmcs_enabled; +} +#endif /* __KVM_X86_VMX_H */
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 7/33 KVM: nVMX: Refactor unsupported eVMCS controls logic to use 2-d array
In reply to Vitaly KuznetsovRefactor the handling of unsupported eVMCS to use a 2-d array to store the set of unsupported controls. KVM's handling of eVMCS is completely broken as there is no way for userspace to query which features are unsupported, nor does KVM prevent userspace from attempting to enable unsupported features. A future commit will remedy that by filtering and enforcing unsupported features when eVMCS, but that needs to be opt-in from userspace to avoid breakage, i.e. KVM needs to maintain its legacy behavior by snapshotting the exact set of controls that are currently (un)supported by eVMCS.
No functional change intended.
--- arch/x86/kvm/vmx/evmcs.c | 60 +++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 10 deletions(-)
arch/x86/kvm/vmx/evmcs.c +50 -10
@@ -345,6 +345,45 @@ uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu)return 0 ; } +enum evmcs_revision { + EVMCSv1_LEGACY, +NR_EVMCS_REVISIONS , +}; + +enum evmcs_ctrl_type { +EVMCS_EXIT_CTRLS , +EVMCS_ENTRY_CTRLS , +EVMCS_2NDEXEC , +EVMCS_PINCTRL , +EVMCS_VMFUNC , +NR_EVMCS_CTRLS , +}; + +static const u32 evmcs_unsupported_ctrls[NR_EVMCS_CTRLS ][NR_EVMCS_REVISIONS ] = { + [EVMCS_EXIT_CTRLS ] = { + [EVMCSv1_LEGACY] =EVMCS1_UNSUPPORTED_VMEXIT_CTRL , + }, + [EVMCS_ENTRY_CTRLS ] = { + [EVMCSv1_LEGACY] =EVMCS1_UNSUPPORTED_VMENTRY_CTRL , + }, + [EVMCS_2NDEXEC ] = { + [EVMCSv1_LEGACY] =EVMCS1_UNSUPPORTED_2NDEXEC , + }, + [EVMCS_PINCTRL ] = { + [EVMCSv1_LEGACY] =EVMCS1_UNSUPPORTED_PINCTRL , + }, + [EVMCS_VMFUNC ] = { + [EVMCSv1_LEGACY] =EVMCS1_UNSUPPORTED_VMFUNC , + }, +}; + +static u32 evmcs_get_unsupported_ctls (enum evmcs_ctrl_type ctrl_type) +{ +enum evmcs_revision evmcs_rev = EVMCSv1_LEGACY; + +return evmcs_unsupported_ctrls[ctrl_type][evmcs_rev]; +} +void nested_evmcs_filter_control_msr (u32 msr_index,u64 *pdata) {u32 ctl_low = (u32)*pdata;
@@ -357,21 +396,21 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)switch (msr_index) {case MSR_IA32_VMX_EXIT_CTLS :case MSR_IA32_VMX_TRUE_EXIT_CTLS : - ctl_high &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL ; + ctl_high &= ~evmcs_get_unsupported_ctls (EVMCS_EXIT_CTRLS );break ;case MSR_IA32_VMX_ENTRY_CTLS :case MSR_IA32_VMX_TRUE_ENTRY_CTLS : - ctl_high &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL ; + ctl_high &= ~evmcs_get_unsupported_ctls (EVMCS_ENTRY_CTRLS );break ;case MSR_IA32_VMX_PROCBASED_CTLS2 : - ctl_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC ; + ctl_high &= ~evmcs_get_unsupported_ctls (EVMCS_2NDEXEC );break ;case MSR_IA32_VMX_TRUE_PINBASED_CTLS :case MSR_IA32_VMX_PINBASED_CTLS : - ctl_high &= ~EVMCS1_UNSUPPORTED_PINCTRL ; + ctl_high &= ~evmcs_get_unsupported_ctls (EVMCS_PINCTRL );break ;case MSR_IA32_VMX_VMFUNC : - ctl_low &= ~EVMCS1_UNSUPPORTED_VMFUNC ; + ctl_low &= ~evmcs_get_unsupported_ctls (EVMCS_VMFUNC );break ; }
@@ -384,7 +423,7 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12)u32 unsupp_ctl; unsupp_ctl = vmcs12->pin_based_vm_exec_control & -EVMCS1_UNSUPPORTED_PINCTRL ; +evmcs_get_unsupported_ctls (EVMCS_PINCTRL );if (unsupp_ctl) { trace_kvm_nested_vmenter_failed( "eVMCS: unsupported pin-based VM-execution controls",
@@ -393,7 +432,7 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) } unsupp_ctl = vmcs12->secondary_vm_exec_control & -EVMCS1_UNSUPPORTED_2NDEXEC ; +evmcs_get_unsupported_ctls (EVMCS_2NDEXEC );if (unsupp_ctl) { trace_kvm_nested_vmenter_failed( "eVMCS: unsupported secondary VM-execution controls",
@@ -402,7 +441,7 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) } unsupp_ctl = vmcs12->vm_exit_controls & -EVMCS1_UNSUPPORTED_VMEXIT_CTRL ; +evmcs_get_unsupported_ctls (EVMCS_EXIT_CTRLS );if (unsupp_ctl) { trace_kvm_nested_vmenter_failed( "eVMCS: unsupported VM-exit controls",
@@ -411,7 +450,7 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) } unsupp_ctl = vmcs12->vm_entry_controls & -EVMCS1_UNSUPPORTED_VMENTRY_CTRL ; +evmcs_get_unsupported_ctls (EVMCS_ENTRY_CTRLS );if (unsupp_ctl) { trace_kvm_nested_vmenter_failed( "eVMCS: unsupported VM-entry controls",
@@ -419,7 +458,8 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) ret = -EINVAL ; } - unsupp_ctl = vmcs12->vm_function_control &EVMCS1_UNSUPPORTED_VMFUNC ; + unsupp_ctl = vmcs12->vm_function_control & +evmcs_get_unsupported_ctls (EVMCS_VMFUNC );if (unsupp_ctl) { trace_kvm_nested_vmenter_failed( "eVMCS: unsupported VM-function controls",
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 8/33 KVM: nVMX: Use CC() macro to handle eVMCS unsupported controls checks
In reply to Vitaly KuznetsovFrom: Sean Christopherson <[email protected]>
Locally #define and use the nested virtualization Consistency Check (CC) macro to handle eVMCS unsupported controls checks. Using the macro loses the existing printing of the unsupported controls, but that's a feature and not a bug. The existing approach is flawed because the @err param to trace_kvm_nested_vmenter_failed() is the error code, not the error value.
The eVMCS trickery mostly works as __print_symbolic() falls back to printing the raw hex value, but that subtly relies on not having a match between the unsupported value and VMX_VMENTER_INSTRUCTION_ERRORS.
If it's really truly necessary to snapshot the bad value, then the tracepoint can be extended in the future.
--- arch/x86/kvm/vmx/evmcs.c | 68 ++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 44 deletions(-)
arch/x86/kvm/vmx/evmcs.c +24 -44
@@ -10,6 +10,8 @@#include "vmx.h" #include "trace.h" +#define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK +DEFINE_STATIC_KEY_FALSE (enable_evmcs);#define EVMCS1_OFFSET (x) offsetof(struct hv_enlightened_vmcs, x)
@@ -417,57 +419,35 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata) *pdata = ctl_low | ((u64 )ctl_high <<32 ); } +static bool nested_evmcs_is_valid_controls (enum evmcs_ctrl_type ctrl_type, +u32 val) +{ +return !(val &evmcs_get_unsupported_ctls (ctrl_type)); +} +int nested_evmcs_check_controls (struct vmcs12 *vmcs12) { -int ret =0 ; -u32 unsupp_ctl; - - unsupp_ctl = vmcs12->pin_based_vm_exec_control & -evmcs_get_unsupported_ctls (EVMCS_PINCTRL ); -if (unsupp_ctl) { -trace_kvm_nested_vmenter_failed ( -"eVMCS: unsupported pin-based VM-execution controls" , - unsupp_ctl); - ret = -EINVAL ; - } +if (CC (!nested_evmcs_is_valid_controls (EVMCS_PINCTRL , + vmcs12->pin_based_vm_exec_control))) +return -EINVAL ; - unsupp_ctl = vmcs12->secondary_vm_exec_control & -evmcs_get_unsupported_ctls (EVMCS_2NDEXEC ); -if (unsupp_ctl) { -trace_kvm_nested_vmenter_failed ( -"eVMCS: unsupported secondary VM-execution controls" , - unsupp_ctl); - ret = -EINVAL ; - } +if (CC (!nested_evmcs_is_valid_controls (EVMCS_2NDEXEC , + vmcs12->secondary_vm_exec_control))) +return -EINVAL ; - unsupp_ctl = vmcs12->vm_exit_controls & -evmcs_get_unsupported_ctls (EVMCS_EXIT_CTRLS ); -if (unsupp_ctl) { -trace_kvm_nested_vmenter_failed ( -"eVMCS: unsupported VM-exit controls" , - unsupp_ctl); - ret = -EINVAL ; - } +if (CC (!nested_evmcs_is_valid_controls (EVMCS_EXIT_CTRLS , + vmcs12->vm_exit_controls))) +return -EINVAL ; - unsupp_ctl = vmcs12->vm_entry_controls & -evmcs_get_unsupported_ctls (EVMCS_ENTRY_CTRLS ); -if (unsupp_ctl) { -trace_kvm_nested_vmenter_failed ( -"eVMCS: unsupported VM-entry controls" , - unsupp_ctl); - ret = -EINVAL ; - } +if (CC (!nested_evmcs_is_valid_controls (EVMCS_ENTRY_CTRLS , + vmcs12->vm_entry_controls))) +return -EINVAL ; - unsupp_ctl = vmcs12->vm_function_control & -evmcs_get_unsupported_ctls (EVMCS_VMFUNC ); -if (unsupp_ctl) { -trace_kvm_nested_vmenter_failed ( -"eVMCS: unsupported VM-function controls" , - unsupp_ctl); - ret = -EINVAL ; - } +if (CC (!nested_evmcs_is_valid_controls (EVMCS_VMFUNC , + vmcs12->vm_function_control))) +return -EINVAL ; -return ret; +return 0 ; } int nested_enable_evmcs(struct kvm_vcpu *vcpu,
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 9/33 KVM: VMX: Define VMCS-to-EVMCS conversion for the new fields
In reply to Vitaly KuznetsovEnlightened VMCS v1 definition was updated with new fields, support them in KVM by defining VMCS-to-EVMCS conversion.
Note: SSP, CET and Guest LBR features are not supported by KVM yet and the corresponding fields are not defined in 'enum vmcs_field', leave them commented out for now.
--- arch/x86/kvm/vmx/evmcs.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
arch/x86/kvm/vmx/evmcs.c +26 -0
@@ -30,6 +30,8 @@ const struct evmcs_field vmcs_field_to_evmcs_1[] = { HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),EVMCS1_FIELD (HOST_IA32_EFER , host_ia32_efer,HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1 ), +EVMCS1_FIELD (HOST_IA32_PERF_GLOBAL_CTRL , host_ia32_perf_global_ctrl, +HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1 ),EVMCS1_FIELD (HOST_CR0 , host_cr0,HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1 ), EVMCS1_FIELD(HOST_CR3, host_cr3,
@@ -80,6 +82,8 @@ const struct evmcs_field vmcs_field_to_evmcs_1[] = { HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),EVMCS1_FIELD (GUEST_IA32_EFER , guest_ia32_efer,HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1 ), +EVMCS1_FIELD (GUEST_IA32_PERF_GLOBAL_CTRL , guest_ia32_perf_global_ctrl, +HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1 ),EVMCS1_FIELD (GUEST_PDPTR0 , guest_pdptr0,HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1 ), EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
@@ -128,6 +132,28 @@ const struct evmcs_field vmcs_field_to_evmcs_1[] = { HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),EVMCS1_FIELD (XSS_EXIT_BITMAP , xss_exit_bitmap,HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2 ), +EVMCS1_FIELD (ENCLS_EXITING_BITMAP , encls_exiting_bitmap, +HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2 ), +EVMCS1_FIELD (TSC_MULTIPLIER , tsc_multiplier, +HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2 ), +/* +* Not used by KVM: +* +* EVMCS1_FIELD(0x00006828, guest_ia32_s_cet, +* HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), +* EVMCS1_FIELD(0x0000682A, guest_ssp, +* HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC), +* EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr, +* HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), +* EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl, +* HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), +* EVMCS1_FIELD(0x00006C18, host_ia32_s_cet, +* HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), +* EVMCS1_FIELD(0x00006C1A, host_ssp, +* HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), +* EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr, +* HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), +*/ /* 64 bit read only */ EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 10/33 KVM: nVMX: Support several new fields in eVMCSv1
In reply to Vitaly KuznetsovEnlightened VMCS v1 definition was updated with new fields, add support for them for Hyper-V on KVM.
Note: SSP, CET and Guest LBR features are not supported by KVM yet and 'struct vmcs12' has no corresponding fields.
--- arch/x86/kvm/vmx/nested.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
arch/x86/kvm/vmx/nested.c +31 -0
@@ -1607,6 +1607,10 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields vmcs12->guest_rflags = evmcs->guest_rflags; vmcs12->guest_interruptibility_info = evmcs->guest_interruptibility_info; +/* +* Not present in struct vmcs12: +* vmcs12->guest_ssp = evmcs->guest_ssp; +*/ } if (unlikely(!(hv_clean_fields &
@@ -1653,6 +1657,13 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields vmcs12->host_fs_selector = evmcs->host_fs_selector; vmcs12->host_gs_selector = evmcs->host_gs_selector; vmcs12->host_tr_selector = evmcs->host_tr_selector; + vmcs12->host_ia32_perf_global_ctrl = evmcs->host_ia32_perf_global_ctrl; +/* +* Not present in struct vmcs12: +* vmcs12->host_ia32_s_cet = evmcs->host_ia32_s_cet; +* vmcs12->host_ssp = evmcs->host_ssp; +* vmcs12->host_ia32_int_ssp_table_addr = evmcs->host_ia32_int_ssp_table_addr; +*/ } if (unlikely(!(hv_clean_fields &
@@ -1720,6 +1731,8 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields vmcs12->tsc_offset = evmcs->tsc_offset; vmcs12->virtual_apic_page_addr = evmcs->virtual_apic_page_addr; vmcs12->xss_exit_bitmap = evmcs->xss_exit_bitmap; + vmcs12->encls_exiting_bitmap = evmcs->encls_exiting_bitmap; + vmcs12->tsc_multiplier = evmcs->tsc_multiplier; } if (unlikely(!(hv_clean_fields &
@@ -1767,6 +1780,13 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields vmcs12->guest_bndcfgs = evmcs->guest_bndcfgs; vmcs12->guest_activity_state = evmcs->guest_activity_state; vmcs12->guest_sysenter_cs = evmcs->guest_sysenter_cs; + vmcs12->guest_ia32_perf_global_ctrl = evmcs->guest_ia32_perf_global_ctrl; +/* +* Not present in struct vmcs12: +* vmcs12->guest_ia32_s_cet = evmcs->guest_ia32_s_cet; +* vmcs12->guest_ia32_lbr_ctl = evmcs->guest_ia32_lbr_ctl; +* vmcs12->guest_ia32_int_ssp_table_addr = evmcs->guest_ia32_int_ssp_table_addr; +*/ }/*
@@ -1869,12 +1889,23 @@ static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)* evmcs->vm_exit_msr_store_count = vmcs12->vm_exit_msr_store_count; * evmcs->vm_exit_msr_load_count = vmcs12->vm_exit_msr_load_count; * evmcs->vm_entry_msr_load_count = vmcs12->vm_entry_msr_load_count; +* evmcs->guest_ia32_perf_global_ctrl = vmcs12->guest_ia32_perf_global_ctrl; +* evmcs->host_ia32_perf_global_ctrl = vmcs12->host_ia32_perf_global_ctrl; +* evmcs->encls_exiting_bitmap = vmcs12->encls_exiting_bitmap; +* evmcs->tsc_multiplier = vmcs12->tsc_multiplier; * * Not present in struct vmcs12: * evmcs->exit_io_instruction_ecx = vmcs12->exit_io_instruction_ecx; * evmcs->exit_io_instruction_esi = vmcs12->exit_io_instruction_esi; * evmcs->exit_io_instruction_edi = vmcs12->exit_io_instruction_edi; * evmcs->exit_io_instruction_eip = vmcs12->exit_io_instruction_eip; +* evmcs->host_ia32_s_cet = vmcs12->host_ia32_s_cet; +* evmcs->host_ssp = vmcs12->host_ssp; +* evmcs->host_ia32_int_ssp_table_addr = vmcs12->host_ia32_int_ssp_table_addr; +* evmcs->guest_ia32_s_cet = vmcs12->guest_ia32_s_cet; +* evmcs->guest_ia32_lbr_ctl = vmcs12->guest_ia32_lbr_ctl; +* evmcs->guest_ia32_int_ssp_table_addr = vmcs12->guest_ia32_int_ssp_table_addr; +* evmcs->guest_ssp = vmcs12->guest_ssp; */ evmcs->guest_es_selector = vmcs12->guest_es_selector;
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 11/33 KVM: x86: hyper-v: Cache HYPERV_CPUID_NESTED_FEATURES CPUID leaf
In reply to Vitaly KuznetsovKVM has to check guest visible HYPERV_CPUID_NESTED_FEATURES.EBX CPUID leaf to know which Enlightened VMCS definition to use (original or 2022 update). Cache the leaf along with other Hyper-V CPUID feature leaves to make the check quick.
--- arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/hyperv.c | 6 ++++++ 2 files changed, 8 insertions(+)
arch/x86/include/asm/kvm_host.h +2 -0
@@ -615,6 +615,8 @@ struct kvm_vcpu_hv {u32 enlightenments_eax;/* HYPERV_CPUID_ENLIGHTMENT_INFO.EAX */ u32 enlightenments_ebx;/* HYPERV_CPUID_ENLIGHTMENT_INFO.EBX */ u32 syndbg_cap_eax;/* HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX */ +u32 nested_eax;/* HYPERV_CPUID_NESTED_FEATURES.EAX */ +u32 nested_ebx;/* HYPERV_CPUID_NESTED_FEATURES.EBX */ } cpuid_cache; };
arch/x86/kvm/hyperv.c +6 -0
@@ -2018,6 +2018,12 @@ void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu, bool hyperv_enabled) entry =kvm_find_cpuid_entry (vcpu,HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES );if (entry) hv_vcpu->cpuid_cache.syndbg_cap_eax = entry->eax; + + entry =kvm_find_cpuid_entry (vcpu,HYPERV_CPUID_NESTED_FEATURES ); +if (entry) { + hv_vcpu->cpuid_cache.nested_eax = entry->eax; + hv_vcpu->cpuid_cache.nested_ebx = entry->ebx; + } }int kvm_hv_set_enforce_cpuid (struct kvm_vcpu *vcpu,bool enforce)
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 12/33 KVM: selftests: Add ENCLS_EXITING_BITMAP{,HIGH} VMCS fields
In reply to Vitaly KuznetsovThe updated Enlightened VMCS definition has 'encls_exiting_bitmap' field which needs mapping to VMCS, add the missing encoding.
--- tools/testing/selftests/kvm/include/x86_64/vmx.h | 2 ++ 1 file changed, 2 insertions(+)
tools/testing/selftests/kvm/include/x86_64/vmx.h +2 -0
@@ -208,6 +208,8 @@ enum vmcs_field {VMWRITE_BITMAP_HIGH =0x00002029 ,XSS_EXIT_BITMAP =0x0000202C ,XSS_EXIT_BITMAP_HIGH =0x0000202D , +ENCLS_EXITING_BITMAP =0x0000202E , +ENCLS_EXITING_BITMAP_HIGH =0x0000202F ,TSC_MULTIPLIER =0x00002032 ,TSC_MULTIPLIER_HIGH =0x00002033 , GUEST_PHYSICAL_ADDRESS = 0x00002400,
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 13/33 KVM: selftests: Switch to updated eVMCSv1 definition
In reply to Vitaly KuznetsovUpdate Enlightened VMCS definition in selftests from KVM.
--- .../selftests/kvm/include/x86_64/evmcs.h | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-)
tools/testing/selftests/kvm/include/x86_64/evmcs.h +42 -3
@@ -203,14 +203,25 @@ struct hv_enlightened_vmcs { u32 reserved:30; } hv_enlightenments_control;u32 hv_vp_id; - +u32 padding32_2;u64 hv_vm_id;u64 partition_assist_page;u64 padding64_4[4 ];u64 guest_bndcfgs; -u64 padding64_5[7 ]; +u64 guest_ia32_perf_global_ctrl; +u64 guest_ia32_s_cet; +u64 guest_ssp; +u64 guest_ia32_int_ssp_table_addr; +u64 guest_ia32_lbr_ctl; +u64 padding64_5[2 ];u64 xss_exit_bitmap; -u64 padding64_6[7 ]; +u64 encls_exiting_bitmap; +u64 host_ia32_perf_global_ctrl; +u64 tsc_multiplier; +u64 host_ia32_s_cet; +u64 host_ssp; +u64 host_ia32_int_ssp_table_addr; +u64 padding64_6; };#define HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE 0
@@ -656,6 +667,18 @@ static inline int evmcs_vmread(uint64_t encoding, uint64_t *value)case VIRTUAL_PROCESSOR_ID : *value = current_evmcs->virtual_processor_id;break ; +case HOST_IA32_PERF_GLOBAL_CTRL : + *value = current_evmcs->host_ia32_perf_global_ctrl; +break ; +case GUEST_IA32_PERF_GLOBAL_CTRL : + *value = current_evmcs->guest_ia32_perf_global_ctrl; +break ; +case ENCLS_EXITING_BITMAP : + *value = current_evmcs->encls_exiting_bitmap; +break ; +case TSC_MULTIPLIER : + *value = current_evmcs->tsc_multiplier; +break ;default :return 1 ; }
@@ -1169,6 +1192,22 @@ static inline int evmcs_vmwrite(uint64_t encoding, uint64_t value) current_evmcs->virtual_processor_id = value; current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT ;break ; +case HOST_IA32_PERF_GLOBAL_CTRL : + current_evmcs->host_ia32_perf_global_ctrl = value; + current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1 ; +break ; +case GUEST_IA32_PERF_GLOBAL_CTRL : + current_evmcs->guest_ia32_perf_global_ctrl = value; + current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1 ; +break ; +case ENCLS_EXITING_BITMAP : + current_evmcs->encls_exiting_bitmap = value; + current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2 ; +break ; +case TSC_MULTIPLIER : + current_evmcs->tsc_multiplier = value; + current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2 ; +break ;default :return 1 ; }
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 14/33 KVM: nVMX: WARN once and fail VM-Enter if eVMCS sees VMFUNC[63:32] != 0
In reply to Vitaly KuznetsovFrom: Sean Christopherson <[email protected]>
WARN and reject nested VM-Enter if KVM is using eVMCS and manages to allow a non-zero value in the upper 32 bits of VM-function controls. The eVMCS code assumes all inputs are 32-bit values and subtly drops the upper bits. WARN instead of adding proper "support", it's unlikely the upper bits will be defined/used in the next decade.
--- arch/x86/kvm/vmx/evmcs.c | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/x86/kvm/vmx/evmcs.c +8 -0
@@ -469,6 +469,14 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) vmcs12->vm_entry_controls)))return -EINVAL ; +/* +* VM-Func controls are 64-bit, but KVM currently doesn't support any +* controls in bits 63:32, i.e. dropping those bits on the consistency +* check is intentional. +*/ +if (WARN_ON_ONCE (vmcs12->vm_function_control >>32 )) +return -EINVAL ; +if (CC (!nested_evmcs_is_valid_controls (EVMCS_VMFUNC , vmcs12->vm_function_control)))return -EINVAL ;
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 15/33 KVM: nVMX: Support PERF_GLOBAL_CTRL with enlightened VMCS
In reply to Vitaly KuznetsovEnlightened VMCS v1 got updated and now includes the required fields for loading PERF_GLOBAL_CTRL upon VMENTER/VMEXIT features. For KVM on Hyper-V enablement, KVM can just observe VMX control MSRs and use the features (with or without eVMCS) when possible.
Hyper-V on KVM is messier as Windows 11 guests fail to boot if the controls are advertised and a new PV feature flag, CPUID.0x4000000A.EBX BIT(0), is not set. Honor the Hyper-V CPUID feature flag to play nice with Windows guests.
--- arch/x86/kvm/hyperv.c | 2 +- arch/x86/kvm/vmx/evmcs.c | 30 +++++++++++++++++++++++++++--- arch/x86/kvm/vmx/evmcs.h | 9 +++------ arch/x86/kvm/vmx/vmx.c | 2 +- 4 files changed, 32 insertions(+), 11 deletions(-)
arch/x86/kvm/hyperv.c +1 -1
@@ -2546,7 +2546,7 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,case HYPERV_CPUID_NESTED_FEATURES : ent->eax = evmcs_ver; ent->eax |=HV_X64_NESTED_MSR_BITMAP ; - + ent->ebx |=HV_X64_NESTED_EVMCS1_PERF_GLOBAL_CTRL ;break ;case HYPERV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS :
arch/x86/kvm/vmx/evmcs.c +27 -3
@@ -412,10 +412,28 @@ static u32 evmcs_get_unsupported_ctls(enum evmcs_ctrl_type ctrl_type)return evmcs_unsupported_ctrls[ctrl_type][evmcs_rev]; } -void nested_evmcs_filter_control_msr (u32 msr_index,u64 *pdata) +static bool evmcs_has_perf_global_ctrl (struct kvm_vcpu *vcpu) +{ +struct kvm_vcpu_hv *hv_vcpu =to_hv_vcpu (vcpu); + +/* +* PERF_GLOBAL_CTRL has a quirk where some Windows guests may fail to +* boot if a PV CPUID feature flag is not also set. Treat the fields +* as unsupported if the flag is not set in guest CPUID. This should +* be called only for guest accesses, and all guest accesses should be +* gated on Hyper-V being enabled and initialized. +*/ +if (WARN_ON_ONCE (!hv_vcpu)) +return false; + +return hv_vcpu->cpuid_cache.nested_ebx &HV_X64_NESTED_EVMCS1_PERF_GLOBAL_CTRL ; +} + +void nested_evmcs_filter_control_msr (struct kvm_vcpu *vcpu,u32 msr_index,u64 *pdata) {u32 ctl_low = (u32)*pdata;u32 ctl_high = (u32)(*pdata >>32 ); +u32 unsupported_ctrls;/* * Hyper-V 2016 and 2019 try using these features even when eVMCS
@@ -424,11 +442,17 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)switch (msr_index) {case MSR_IA32_VMX_EXIT_CTLS :case MSR_IA32_VMX_TRUE_EXIT_CTLS : - ctl_high &= ~evmcs_get_unsupported_ctls (EVMCS_EXIT_CTRLS ); + unsupported_ctrls =evmcs_get_unsupported_ctls (EVMCS_EXIT_CTRLS ); +if (!evmcs_has_perf_global_ctrl (vcpu)) + unsupported_ctrls |=VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL ; + ctl_high &= ~unsupported_ctrls;break ;case MSR_IA32_VMX_ENTRY_CTLS :case MSR_IA32_VMX_TRUE_ENTRY_CTLS : - ctl_high &= ~evmcs_get_unsupported_ctls (EVMCS_ENTRY_CTRLS ); + unsupported_ctrls =evmcs_get_unsupported_ctls (EVMCS_ENTRY_CTRLS ); +if (!evmcs_has_perf_global_ctrl (vcpu)) + unsupported_ctrls |=VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL ; + ctl_high &= ~unsupported_ctrls;break ;case MSR_IA32_VMX_PROCBASED_CTLS2 : ctl_high &= ~evmcs_get_unsupported_ctls (EVMCS_2NDEXEC );
arch/x86/kvm/vmx/evmcs.h +3 -6
@@ -42,8 +42,6 @@ DECLARE_STATIC_KEY_FALSE(enable_evmcs);* PLE_GAP = 0x00004020, * PLE_WINDOW = 0x00004022, * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, -* GUEST_IA32_PERF_GLOBAL_CTRL = 0x00002808, -* HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04, * * Currently unsupported in KVM: * GUEST_IA32_RTIT_CTL = 0x00002814,
@@ -61,9 +59,8 @@ DECLARE_STATIC_KEY_FALSE(enable_evmcs); SECONDARY_EXEC_TSC_SCALING | \ SECONDARY_EXEC_PAUSE_LOOP_EXITING)#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL \ - (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ - VM_EXIT_SAVE_VMX_PREEMPTION_TIMER) -#define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) + (VM_EXIT_SAVE_VMX_PREEMPTION_TIMER) +#define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (0)#define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)struct evmcs_field {
@@ -243,7 +240,7 @@ bool nested_enlightened_vmentry(struct kvm_vcpu *vcpu, u64 *evmcs_gpa);uint16_t nested_get_evmcs_version (struct kvm_vcpu *vcpu);int nested_enable_evmcs (struct kvm_vcpu *vcpu,uint16_t *vmcs_version); -void nested_evmcs_filter_control_msr (u32 msr_index,u64 *pdata); +void nested_evmcs_filter_control_msr (struct kvm_vcpu *vcpu,u32 msr_index,u64 *pdata);int nested_evmcs_check_controls (struct vmcs12 *vmcs12);#endif /* __KVM_X86_VMX_EVMCS_H */
arch/x86/kvm/vmx/vmx.c +1 -1
@@ -1931,7 +1931,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)* features out. */ if (!msr_info->host_initiated &&guest_cpuid_has_evmcs (vcpu)) -nested_evmcs_filter_control_msr (msr_info->index, +nested_evmcs_filter_control_msr (vcpu, msr_info->index, &msr_info->data);break ;case MSR_IA32_RTIT_CTL :
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 16/33 KVM: VMX: Get rid of eVMCS specific VMX controls sanitization
In reply to Vitaly KuznetsovWith the updated eVMCSv1 definition, there's no known 'problematic' controls which are exposed in VMX control MSRs but are not present in
eVMCSv1: all known Hyper-V versions either don't expose the new fields by not setting bits in the VMX feature controls or support the new eVMCS revision.
Get rid of VMX control MSRs filtering for KVM on Hyper-V.
Note: VMX control MSRs filtering for Hyper-V on KVM (nested_evmcs_filter_control_msr()) stays as even the updated eVMCSv1 definition doesn't have all the features implemented by KVM and some fields are still missing. Moreover, nested_evmcs_filter_control_msr() has to support the original eVMCSv1 version when VMM wishes so.
--- arch/x86/kvm/vmx/evmcs.c | 13 ------------- arch/x86/kvm/vmx/evmcs.h | 1 - arch/x86/kvm/vmx/vmx.c | 5 ----- 3 files changed, 19 deletions(-)
arch/x86/kvm/vmx/evmcs.c +0 -13
@@ -322,19 +322,6 @@ const struct evmcs_field vmcs_field_to_evmcs_1[] = { };const unsigned int nr_evmcs_1_fields =ARRAY_SIZE (vmcs_field_to_evmcs_1); -#if IS_ENABLED (CONFIG_HYPERV ) -__init void evmcs_sanitize_exec_ctrls (struct vmcs_config *vmcs_conf) -{ - vmcs_conf->cpu_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_EXEC_CTRL ; - vmcs_conf->pin_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_PINCTRL ; - vmcs_conf->cpu_based_2nd_exec_ctrl &= ~EVMCS1_UNSUPPORTED_2NDEXEC ; - vmcs_conf->cpu_based_3rd_exec_ctrl =0 ; - - vmcs_conf->vmexit_ctrl &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL ; - vmcs_conf->vmentry_ctrl &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL ; -} -#endif -bool nested_enlightened_vmentry (struct kvm_vcpu *vcpu,u64 *evmcs_gpa) {struct hv_vp_assist_page assist_page;
arch/x86/kvm/vmx/evmcs.h +0 -1
@@ -209,7 +209,6 @@ static inline void evmcs_load(u64 phys_addr) vp_ap->enlighten_vmentry =1 ; } -__init void evmcs_sanitize_exec_ctrls (struct vmcs_config *vmcs_conf);#else /* !IS_ENABLED(CONFIG_HYPERV) */ static __always_inline void evmcs_write64(unsigned long field, u64 value) {}static inline void evmcs_write32 (unsigned long field,u32 value) {}
arch/x86/kvm/vmx/vmx.c +0 -5
@@ -2766,11 +2766,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, vmcs_conf->vmexit_ctrl = _vmexit_control; vmcs_conf->vmentry_ctrl = _vmentry_control; -#if IS_ENABLED (CONFIG_HYPERV ) -if (enlightened_vmcs) -evmcs_sanitize_exec_ctrls (vmcs_conf); -#endif -return 0 ; }
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 17/33 KVM: nVMX: Don't propagate vmcs12's PERF_GLOBAL_CTRL settings to vmcs02
In reply to Vitaly KuznetsovFrom: Sean Christopherson <[email protected]>
Don't propagate vmcs12's VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL to vmcs02. KVM doesn't disallow L1 from using VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL even when KVM itself doesn't use the control, e.g. due to the various CPU errata that where the MSR can be corrupted on VM-Exit.
Preserve KVM's (vmcs01) setting to hopefully avoid having to toggle the bit in vmcs02 at a later point. E.g. if KVM is loading PERF_GLOBAL_CTRL when running L1, then odds are good KVM will also load the MSR when running L2.
--- arch/x86/kvm/vmx/nested.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/x86/kvm/vmx/nested.c +6 -1
@@ -2359,9 +2359,14 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0* are emulated by vmx_set_efer() in prepare_vmcs02(), but speculate * on the related bits (if supported by the CPU) in the hope that * we can avoid VMWrites during vmx_set_efer(). +* +* Similarly, take vmcs01's PERF_GLOBAL_CTRL in the hope that if KVM is +* loading PERF_GLOBAL_CTRL via the VMCS for L1, then KVM will want to +* do the same for L2. */ exec_control =__vm_entry_controls_get (vmcs01); - exec_control |= vmcs12->vm_entry_controls; + exec_control |= (vmcs12->vm_entry_controls & + ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL ); exec_control &= ~(VM_ENTRY_IA32E_MODE |VM_ENTRY_LOAD_IA32_EFER );if (cpu_has_load_ia32_efer ()) {if (guest_efer &EFER_LMA )
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 18/33 KVM: nVMX: Always emulate PERF_GLOBAL_CTRL VM-Entry/VM-Exit controls
In reply to Vitaly KuznetsovFrom: Sean Christopherson <[email protected]>
Advertise VM_{ENTRY,EXIT}_LOAD_IA32_PERF_GLOBAL_CTRL as being supported for nested VMs irrespective of hardware support. KVM fully emulates the controls, i.e. manually emulates MSR writes on entry/exit, and never propagates the guest settings directly to vmcs02.
In addition to allowing L1 VMMs to use the controls on older hardware, unconditionally advertising the controls will also allow KVM to use its vmcs01 configuration as the basis for the nested VMX configuration without causing a regression (due the errata which causes KVM to "hide" the control from vmcs01 but not vmcs12).
--- arch/x86/kvm/vmx/nested.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
arch/x86/kvm/vmx/nested.c +6 -5
@@ -6602,11 +6602,12 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)VM_EXIT_HOST_ADDR_SPACE_SIZE | #endifVM_EXIT_LOAD_IA32_PAT |VM_EXIT_SAVE_IA32_PAT | -VM_EXIT_CLEAR_BNDCFGS |VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL ; +VM_EXIT_CLEAR_BNDCFGS ; msrs->exit_ctls_high |=VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR |VM_EXIT_LOAD_IA32_EFER |VM_EXIT_SAVE_IA32_EFER | -VM_EXIT_SAVE_VMX_PREEMPTION_TIMER |VM_EXIT_ACK_INTR_ON_EXIT ; +VM_EXIT_SAVE_VMX_PREEMPTION_TIMER |VM_EXIT_ACK_INTR_ON_EXIT | +VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL ;/* We support free control of debug control saving. */ msrs->exit_ctls_low &= ~VM_EXIT_SAVE_DEBUG_CONTROLS ;
@@ -6621,10 +6622,10 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)#ifdef CONFIG_X86_64 VM_ENTRY_IA32E_MODE | #endif -VM_ENTRY_LOAD_IA32_PAT |VM_ENTRY_LOAD_BNDCFGS | -VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL ; +VM_ENTRY_LOAD_IA32_PAT |VM_ENTRY_LOAD_BNDCFGS ; msrs->entry_ctls_high |= - (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR |VM_ENTRY_LOAD_IA32_EFER ); + (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR |VM_ENTRY_LOAD_IA32_EFER | +VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL );/* We support free control of debug control loading. */ msrs->entry_ctls_low &= ~VM_ENTRY_LOAD_DEBUG_CONTROLS ;
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 19/33 KVM: VMX: Check VM_ENTRY_IA32E_MODE in setup_vmcs_config()
In reply to Vitaly KuznetsovVM_ENTRY_IA32E_MODE control is toggled dynamically by vmx_set_efer() and setup_vmcs_config() doesn't check its existence. On the contrary, nested_vmx_setup_ctls_msrs() doesn set it on x86_64. Add the missing check and filter the bit out in vmx_vmentry_ctrl().
No (real) functional change intended as all existing CPUs supporting long mode and VMX are supposed to have it.
--- arch/x86/kvm/vmx/vmx.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
arch/x86/kvm/vmx/vmx.c +11 -3
@@ -2687,6 +2687,9 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, _pin_based_exec_control &= ~PIN_BASED_POSTED_INTR ; min =VM_ENTRY_LOAD_DEBUG_CONTROLS ; +#ifdef CONFIG_X86_64 + min |=VM_ENTRY_IA32E_MODE ; +#endif opt =VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL |VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_LOAD_IA32_EFER |
@@ -4321,9 +4324,14 @@ static u32 vmx_vmentry_ctrl(void)if (vmx_pt_mode_is_system ()) vmentry_ctrl &= ~(VM_ENTRY_PT_CONCEAL_PIP |VM_ENTRY_LOAD_IA32_RTIT_CTL ); -/* Loading of EFER and PERF_GLOBAL_CTRL are toggled dynamically */ -return vmentry_ctrl & - ~(VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL |VM_ENTRY_LOAD_IA32_EFER ); +/* +* IA32e mode, and loading of EFER and PERF_GLOBAL_CTRL are toggled dynamically. +*/ + vmentry_ctrl &= ~(VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | +VM_ENTRY_LOAD_IA32_EFER | +VM_ENTRY_IA32E_MODE ); + +return vmentry_ctrl; }static u32 vmx_vmexit_ctrl (void )
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 20/33 KVM: VMX: Check CPU_BASED_{INTR,NMI}_WINDOW_EXITING in setup_vmcs_config()
In reply to Vitaly KuznetsovCPU_BASED_{INTR,NMI}_WINDOW_EXITING controls are toggled dynamically by vmx_enable_{irq,nmi}_window, handle_interrupt_window(), handle_nmi_window() but setup_vmcs_config() doesn't check their existence. Add the check and filter the controls out in vmx_exec_control().
Note: KVM explicitly supports CPUs without VIRTUAL_NMIS and all these CPUs are supposedly lacking NMI_WINDOW_EXITING too. Adjust cpu_has_virtual_nmis() accordingly.
No functional change intended.
--- arch/x86/kvm/vmx/capabilities.h | 3 ++- arch/x86/kvm/vmx/vmx.c | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx/capabilities.h +2 -1
@@ -82,7 +82,8 @@ static inline bool cpu_has_vmx_basic_inout(void)static inline bool cpu_has_virtual_nmis (void ) { -return vmcs_config.pin_based_exec_ctrl &PIN_BASED_VIRTUAL_NMIS ; +return vmcs_config.pin_based_exec_ctrl &PIN_BASED_VIRTUAL_NMIS && + vmcs_config.cpu_based_exec_ctrl &CPU_BASED_NMI_WINDOW_EXITING ; }static inline bool cpu_has_vmx_preemption_timer (void )
arch/x86/kvm/vmx/vmx.c +7 -1
@@ -2564,10 +2564,12 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,CPU_BASED_MWAIT_EXITING |CPU_BASED_MONITOR_EXITING |CPU_BASED_INVLPG_EXITING | -CPU_BASED_RDPMC_EXITING ; +CPU_BASED_RDPMC_EXITING | +CPU_BASED_INTR_WINDOW_EXITING ; opt =CPU_BASED_TPR_SHADOW |CPU_BASED_USE_MSR_BITMAPS | +CPU_BASED_NMI_WINDOW_EXITING |CPU_BASED_ACTIVATE_SECONDARY_CONTROLS |CPU_BASED_ACTIVATE_TERTIARY_CONTROLS ; if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
@@ -4378,6 +4380,10 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx) {u32 exec_control = vmcs_config.cpu_based_exec_ctrl; +/* INTR_WINDOW_EXITING and NMI_WINDOW_EXITING are toggled dynamically */ + exec_control &= ~(CPU_BASED_INTR_WINDOW_EXITING | +CPU_BASED_NMI_WINDOW_EXITING ); +if (vmx->vcpu.arch.switch_db_regs &KVM_DEBUGREG_WONT_EXIT ) exec_control &= ~CPU_BASED_MOV_DR_EXITING ;
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 21/33 KVM: VMX: Tweak the special handling of SECONDARY_EXEC_ENCLS_EXITING in setup_vmcs_config()
In reply to Vitaly KuznetsovSECONDARY_EXEC_ENCLS_EXITING is the only control which is conditionally added to the 'optional' checklist in setup_vmcs_config() but the special case can be avoided by always checking for its presence first and filtering out the result later.
Note: the situation when SECONDARY_EXEC_ENCLS_EXITING is present but cpu_has_sgx() is false is possible when SGX is "soft-disabled", e.g. if software writes MCE control MSRs or there's an uncorrectable #MC.
--- arch/x86/kvm/vmx/vmx.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
arch/x86/kvm/vmx/vmx.c +6 -3
@@ -2605,9 +2605,9 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,SECONDARY_EXEC_PT_CONCEAL_VMX |SECONDARY_EXEC_ENABLE_VMFUNC |SECONDARY_EXEC_BUS_LOCK_DETECTION | -SECONDARY_EXEC_NOTIFY_VM_EXITING ; -if (cpu_has_sgx ()) - opt2 |=SECONDARY_EXEC_ENCLS_EXITING ; +SECONDARY_EXEC_NOTIFY_VM_EXITING | +SECONDARY_EXEC_ENCLS_EXITING ; +if (adjust_vmx_controls (min2, opt2,MSR_IA32_VMX_PROCBASED_CTLS2 , &_cpu_based_2nd_exec_control) <0 )
@@ -2654,6 +2654,9 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, vmx_cap->vpid =0 ; } +if (!cpu_has_sgx ()) + _cpu_based_2nd_exec_control &= ~SECONDARY_EXEC_ENCLS_EXITING ; +if (_cpu_based_exec_control &CPU_BASED_ACTIVATE_TERTIARY_CONTROLS ) {u64 opt3 =TERTIARY_EXEC_IPI_VIRT ;
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 22/33 KVM: VMX: Don't toggle VM_ENTRY_IA32E_MODE for 32-bit kernels/KVM
In reply to Vitaly KuznetsovFrom: Sean Christopherson <[email protected]>
Don't toggle VM_ENTRY_IA32E_MODE in 32-bit kernels/KVM and instead bug the VM if KVM attempts to run the guest with EFER.LMA=1. KVM doesn't support running 64-bit guests with 32-bit hosts.
--- arch/x86/kvm/vmx/vmx.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/x86/kvm/vmx/vmx.c +5 -0
@@ -3039,10 +3039,15 @@ int vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)return 0 ; vcpu->arch.efer = efer; +#ifdef CONFIG_X86_64 if (efer &EFER_LMA )vm_entry_controls_setbit (vmx,VM_ENTRY_IA32E_MODE );else vm_entry_controls_clearbit (vmx,VM_ENTRY_IA32E_MODE ); +#else +if (KVM_BUG_ON (efer &EFER_LMA , vcpu->kvm)) +return 1 ; +#endif vmx_setup_uret_msrs (vmx);return 0 ;
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 23/33 KVM: VMX: Extend VMX controls macro shenanigans
In reply to Vitaly KuznetsovWhen VMX controls macros are used to set or clear a control bit, make sure that this bit was checked in setup_vmcs_config() and thus is properly reflected in vmcs_config.
Opportunistically drop pointless "< 0" check for adjust_vmx_controls()'s return value.
No functional change intended.
--- arch/x86/kvm/vmx/vmx.c | 114 +++++++----------------------- arch/x86/kvm/vmx/vmx.h | 155 +++++++++++++++++++++++++++++++++++------ 2 files changed, 157 insertions(+), 112 deletions(-)
arch/x86/kvm/vmx/vmx.c +25 -89
@@ -864,7 +864,7 @@ unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx)return flags; } -static void clear_atomic_switch_msr_special (struct vcpu_vmx *vmx, +static __always_inline void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,unsigned long entry,unsigned long exit) {vm_entry_controls_clearbit (vmx, entry);
@@ -922,7 +922,7 @@ static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)vmcs_write32 (VM_EXIT_MSR_LOAD_COUNT , m->host.nr); } -static void add_atomic_switch_msr_special (struct vcpu_vmx *vmx, +static __always_inline void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,unsigned long entry,unsigned long exit,unsigned long guest_val_vmcs,unsigned long host_val_vmcs,u64 guest_val,u64 host_val)
@@ -2525,7 +2525,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, struct vmx_capability *vmx_cap) {u32 vmx_msr_low, vmx_msr_high; -u32 min, opt, min2, opt2;u32 _pin_based_exec_control =0 ;u32 _cpu_based_exec_control =0 ;u32 _cpu_based_2nd_exec_control =0 ;
@@ -2551,29 +2550,11 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, };memset (vmcs_conf,0 ,sizeof (*vmcs_conf)); - min = CPU_BASED_HLT_EXITING | -#ifdef CONFIG_X86_64 -CPU_BASED_CR8_LOAD_EXITING | -CPU_BASED_CR8_STORE_EXITING | -#endif -CPU_BASED_CR3_LOAD_EXITING | -CPU_BASED_CR3_STORE_EXITING | -CPU_BASED_UNCOND_IO_EXITING | -CPU_BASED_MOV_DR_EXITING | -CPU_BASED_USE_TSC_OFFSETTING | -CPU_BASED_MWAIT_EXITING | -CPU_BASED_MONITOR_EXITING | -CPU_BASED_INVLPG_EXITING | -CPU_BASED_RDPMC_EXITING | -CPU_BASED_INTR_WINDOW_EXITING ; - - opt =CPU_BASED_TPR_SHADOW | -CPU_BASED_USE_MSR_BITMAPS | -CPU_BASED_NMI_WINDOW_EXITING | -CPU_BASED_ACTIVATE_SECONDARY_CONTROLS | -CPU_BASED_ACTIVATE_TERTIARY_CONTROLS ; -if (adjust_vmx_controls (min, opt,MSR_IA32_VMX_PROCBASED_CTLS , - &_cpu_based_exec_control) <0 ) + +if (adjust_vmx_controls (KVM_REQUIRED_VMX_CPU_BASED_VM_EXEC_CONTROL , +KVM_OPTIONAL_VMX_CPU_BASED_VM_EXEC_CONTROL , +MSR_IA32_VMX_PROCBASED_CTLS , + &_cpu_based_exec_control))return -EIO ;#ifdef CONFIG_X86_64 if (_cpu_based_exec_control &CPU_BASED_TPR_SHADOW )
@@ -2581,36 +2562,10 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, ~CPU_BASED_CR8_STORE_EXITING ;#endif if (_cpu_based_exec_control &CPU_BASED_ACTIVATE_SECONDARY_CONTROLS ) { - min2 =0 ; - opt2 =SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | -SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | -SECONDARY_EXEC_WBINVD_EXITING | -SECONDARY_EXEC_ENABLE_VPID | -SECONDARY_EXEC_ENABLE_EPT | -SECONDARY_EXEC_UNRESTRICTED_GUEST | -SECONDARY_EXEC_PAUSE_LOOP_EXITING | -SECONDARY_EXEC_DESC | -SECONDARY_EXEC_ENABLE_RDTSCP | -SECONDARY_EXEC_ENABLE_INVPCID | -SECONDARY_EXEC_APIC_REGISTER_VIRT | -SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | -SECONDARY_EXEC_SHADOW_VMCS | -SECONDARY_EXEC_XSAVES | -SECONDARY_EXEC_RDSEED_EXITING | -SECONDARY_EXEC_RDRAND_EXITING | -SECONDARY_EXEC_ENABLE_PML | -SECONDARY_EXEC_TSC_SCALING | -SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | -SECONDARY_EXEC_PT_USE_GPA | -SECONDARY_EXEC_PT_CONCEAL_VMX | -SECONDARY_EXEC_ENABLE_VMFUNC | -SECONDARY_EXEC_BUS_LOCK_DETECTION | -SECONDARY_EXEC_NOTIFY_VM_EXITING | -SECONDARY_EXEC_ENCLS_EXITING ; - -if (adjust_vmx_controls (min2, opt2, +if (adjust_vmx_controls (KVM_REQUIRED_VMX_SECONDARY_VM_EXEC_CONTROL , +KVM_OPTIONAL_VMX_SECONDARY_VM_EXEC_CONTROL ,MSR_IA32_VMX_PROCBASED_CTLS2 , - &_cpu_based_2nd_exec_control) <0 ) + &_cpu_based_2nd_exec_control))return -EIO ; }#ifndef CONFIG_X86_64
@@ -2657,32 +2612,21 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,if (!cpu_has_sgx ()) _cpu_based_2nd_exec_control &= ~SECONDARY_EXEC_ENCLS_EXITING ; -if (_cpu_based_exec_control &CPU_BASED_ACTIVATE_TERTIARY_CONTROLS ) { -u64 opt3 =TERTIARY_EXEC_IPI_VIRT ; - - _cpu_based_3rd_exec_control =adjust_vmx_controls64 (opt3, +if (_cpu_based_exec_control &CPU_BASED_ACTIVATE_TERTIARY_CONTROLS ) + _cpu_based_3rd_exec_control = +adjust_vmx_controls64 (KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL ,MSR_IA32_VMX_PROCBASED_CTLS3 ); - } - min =VM_EXIT_SAVE_DEBUG_CONTROLS |VM_EXIT_ACK_INTR_ON_EXIT ; -#ifdef CONFIG_X86_64 - min |=VM_EXIT_HOST_ADDR_SPACE_SIZE ; -#endif - opt =VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | -VM_EXIT_LOAD_IA32_PAT | -VM_EXIT_LOAD_IA32_EFER | -VM_EXIT_CLEAR_BNDCFGS | -VM_EXIT_PT_CONCEAL_PIP | -VM_EXIT_CLEAR_IA32_RTIT_CTL ; -if (adjust_vmx_controls (min, opt,MSR_IA32_VMX_EXIT_CTLS , - &_vmexit_control) <0 ) +if (adjust_vmx_controls (KVM_REQUIRED_VMX_VM_EXIT_CONTROLS , +KVM_OPTIONAL_VMX_VM_EXIT_CONTROLS , +MSR_IA32_VMX_EXIT_CTLS , + &_vmexit_control))return -EIO ; - min =PIN_BASED_EXT_INTR_MASK |PIN_BASED_NMI_EXITING ; - opt =PIN_BASED_VIRTUAL_NMIS |PIN_BASED_POSTED_INTR | -PIN_BASED_VMX_PREEMPTION_TIMER ; -if (adjust_vmx_controls (min, opt,MSR_IA32_VMX_PINBASED_CTLS , - &_pin_based_exec_control) <0 ) +if (adjust_vmx_controls (KVM_REQUIRED_VMX_PIN_BASED_VM_EXEC_CONTROL , +KVM_OPTIONAL_VMX_PIN_BASED_VM_EXEC_CONTROL , +MSR_IA32_VMX_PINBASED_CTLS , + &_pin_based_exec_control))return -EIO ;if (cpu_has_broken_vmx_preemption_timer ())
@@ -2691,18 +2635,10 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)) _pin_based_exec_control &= ~PIN_BASED_POSTED_INTR; - min =VM_ENTRY_LOAD_DEBUG_CONTROLS ; -#ifdef CONFIG_X86_64 - min |=VM_ENTRY_IA32E_MODE ; -#endif - opt =VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | -VM_ENTRY_LOAD_IA32_PAT | -VM_ENTRY_LOAD_IA32_EFER | -VM_ENTRY_LOAD_BNDCFGS | -VM_ENTRY_PT_CONCEAL_PIP | -VM_ENTRY_LOAD_IA32_RTIT_CTL ; -if (adjust_vmx_controls (min, opt,MSR_IA32_VMX_ENTRY_CTLS , - &_vmentry_control) <0 ) +if (adjust_vmx_controls (KVM_REQUIRED_VMX_VM_ENTRY_CONTROLS , +KVM_OPTIONAL_VMX_VM_ENTRY_CONTROLS , +MSR_IA32_VMX_ENTRY_CTLS , + &_vmentry_control))return -EIO ;for (i =0 ; i <ARRAY_SIZE (vmcs_entry_exit_pairs); i++) {
arch/x86/kvm/vmx/vmx.h +132 -23
161 lines not on this page · raw message
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 24/33 KVM: VMX: Move CPU_BASED_CR8_{LOAD,STORE}_EXITING filtering out of setup_vmcs_config()
In reply to Vitaly KuznetsovAs a preparation to reusing the result of setup_vmcs_config() in nested VMX MSR setup, move CPU_BASED_CR8_{LOAD,STORE}_EXITING filtering to vmx_exec_control().
No functional change intended.
--- arch/x86/kvm/vmx/vmx.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
arch/x86/kvm/vmx/vmx.c +6 -7
@@ -2556,11 +2556,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, MSR_IA32_VMX_PROCBASED_CTLS, &_cpu_based_exec_control))return -EIO ; -#ifdef CONFIG_X86_64 -if (_cpu_based_exec_control &CPU_BASED_TPR_SHADOW ) - _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING & - ~CPU_BASED_CR8_STORE_EXITING ; -#endif if (_cpu_based_exec_control &CPU_BASED_ACTIVATE_SECONDARY_CONTROLS ) { if (adjust_vmx_controls(KVM_REQUIRED_VMX_SECONDARY_VM_EXEC_CONTROL, KVM_OPTIONAL_VMX_SECONDARY_VM_EXEC_CONTROL,
@@ -4331,13 +4326,17 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx)if (vmx->vcpu.arch.switch_db_regs &KVM_DEBUGREG_WONT_EXIT ) exec_control &= ~CPU_BASED_MOV_DR_EXITING ; -if (!cpu_need_tpr_shadow (&vmx->vcpu)) { +if (!cpu_need_tpr_shadow (&vmx->vcpu)) exec_control &= ~CPU_BASED_TPR_SHADOW ; +#ifdef CONFIG_X86_64 +if (exec_control &CPU_BASED_TPR_SHADOW ) + exec_control &= ~(CPU_BASED_CR8_LOAD_EXITING | +CPU_BASED_CR8_STORE_EXITING ); +else exec_control |=CPU_BASED_CR8_STORE_EXITING |CPU_BASED_CR8_LOAD_EXITING ;#endif - }if (!enable_ept) exec_control |=CPU_BASED_CR3_STORE_EXITING | CPU_BASED_CR3_LOAD_EXITING |
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 25/33 KVM: VMX: Add missing VMEXIT controls to vmcs_config
In reply to Vitaly KuznetsovAs a preparation to reusing the result of setup_vmcs_config() in nested VMX MSR setup, add the VMEXIT controls which KVM doesn't use but supports for nVMX to KVM_OPT_VMX_VM_EXIT_CONTROLS and filter them out in vmx_vmexit_ctrl().
No functional change intended.
--- arch/x86/kvm/vmx/vmx.c | 7 +++++++ arch/x86/kvm/vmx/vmx.h | 3 +++ 2 files changed, 10 insertions(+)
arch/x86/kvm/vmx/vmx.c +7 -0
@@ -4279,6 +4279,13 @@ static u32 vmx_vmexit_ctrl(void) {u32 vmexit_ctrl = vmcs_config.vmexit_ctrl; +/* +* Not used by KVM and never set in vmcs01 or vmcs02, but emulated for +* nested virtualization and thus allowed to be set in vmcs12. +*/ + vmexit_ctrl &= ~(VM_EXIT_SAVE_IA32_PAT |VM_EXIT_SAVE_IA32_EFER | +VM_EXIT_SAVE_VMX_PREEMPTION_TIMER ); +if (vmx_pt_mode_is_system ()) vmexit_ctrl &= ~(VM_EXIT_PT_CONCEAL_PIP |VM_EXIT_CLEAR_IA32_RTIT_CTL );
arch/x86/kvm/vmx/vmx.h +3 -0
@@ -508,7 +508,10 @@ static inline u8 vmx_get_rvi(void)#endif #define KVM_OPTIONAL_VMX_VM_EXIT_CONTROLS \ (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ + VM_EXIT_SAVE_IA32_PAT | \ VM_EXIT_LOAD_IA32_PAT | \ + VM_EXIT_SAVE_IA32_EFER | \ + VM_EXIT_SAVE_VMX_PREEMPTION_TIMER | \ VM_EXIT_LOAD_IA32_EFER | \ VM_EXIT_CLEAR_BNDCFGS | \ VM_EXIT_PT_CONCEAL_PIP | \
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 26/33 KVM: VMX: Add missing CPU based VM execution controls to vmcs_config
In reply to Vitaly KuznetsovAs a preparation to reusing the result of setup_vmcs_config() in nested VMX MSR setup, add the CPU based VM execution controls which KVM doesn't use but supports for nVMX to KVM_OPT_VMX_CPU_BASED_VM_EXEC_CONTROL and filter them out in vmx_exec_control().
No functional change intended.
--- arch/x86/kvm/vmx/vmx.c | 9 +++++++++ arch/x86/kvm/vmx/vmx.h | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-)
arch/x86/kvm/vmx/vmx.c +9 -0
@@ -4326,6 +4326,15 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx) {u32 exec_control = vmcs_config.cpu_based_exec_ctrl; +/* +* Not used by KVM, but fully supported for nesting, i.e. are allowed in +* vmcs12 and propagated to vmcs02 when set in vmcs12. +*/ + exec_control &= ~(CPU_BASED_RDTSC_EXITING | +CPU_BASED_USE_IO_BITMAPS | +CPU_BASED_MONITOR_TRAP_FLAG | +CPU_BASED_PAUSE_EXITING ); +/* INTR_WINDOW_EXITING and NMI_WINDOW_EXITING are toggled dynamically */ exec_control &= ~(CPU_BASED_INTR_WINDOW_EXITING |CPU_BASED_NMI_WINDOW_EXITING );
arch/x86/kvm/vmx/vmx.h +5 -1
@@ -549,9 +549,13 @@ static inline u8 vmx_get_rvi(void)#endif #define KVM_OPTIONAL_VMX_CPU_BASED_VM_EXEC_CONTROL \ - (CPU_BASED_TPR_SHADOW | \ + (CPU_BASED_RDTSC_EXITING | \ + CPU_BASED_TPR_SHADOW | \ + CPU_BASED_USE_IO_BITMAPS | \ + CPU_BASED_MONITOR_TRAP_FLAG | \ CPU_BASED_USE_MSR_BITMAPS | \ CPU_BASED_NMI_WINDOW_EXITING | \ + CPU_BASED_PAUSE_EXITING | \ CPU_BASED_ACTIVATE_SECONDARY_CONTROLS | \ CPU_BASED_ACTIVATE_TERTIARY_CONTROLS)
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 27/33 KVM: VMX: Adjust CR3/INVPLG interception for EPT=y at runtime, not setup
In reply to Vitaly KuznetsovFrom: Sean Christopherson <[email protected]>
Clear the CR3 and INVLPG interception controls at runtime based on whether or not EPT is being _used_, as opposed to clearing the bits at setup if EPT is _supported_ in hardware, and then restoring them when EPT is not used. Not mucking with the base config will allow using the base config as the starting point for emulating the VMX capability MSRs.
--- arch/x86/kvm/vmx/vmx.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-)
arch/x86/kvm/vmx/vmx.c +7 -11
@@ -2578,13 +2578,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,rdmsr_safe (MSR_IA32_VMX_EPT_VPID_CAP , &vmx_cap->ept, &vmx_cap->vpid); -if (_cpu_based_2nd_exec_control &SECONDARY_EXEC_ENABLE_EPT ) { -/* CR3 accesses and invlpg don't need to cause VM Exits when EPT -enabled */ - _cpu_based_exec_control &= ~(CPU_BASED_CR3_LOAD_EXITING | -CPU_BASED_CR3_STORE_EXITING | -CPU_BASED_INVLPG_EXITING ); - }else if (vmx_cap->ept) { +if (!(_cpu_based_2nd_exec_control &SECONDARY_EXEC_ENABLE_EPT ) && + vmx_cap->ept) {pr_warn_once ("EPT CAP should not exist if not support " "1-setting enable EPT VM-execution control\n" );
@@ -4353,10 +4348,11 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx) exec_control |=CPU_BASED_CR8_STORE_EXITING |CPU_BASED_CR8_LOAD_EXITING ;#endif -if (!enable_ept) - exec_control |=CPU_BASED_CR3_STORE_EXITING | -CPU_BASED_CR3_LOAD_EXITING | -CPU_BASED_INVLPG_EXITING ; +/* No need to intercept CR3 access or INVPLG when using EPT. */ +if (enable_ept) + exec_control &= ~(CPU_BASED_CR3_LOAD_EXITING | +CPU_BASED_CR3_STORE_EXITING | +CPU_BASED_INVLPG_EXITING );if (kvm_mwait_in_guest (vmx->vcpu.kvm)) exec_control &= ~(CPU_BASED_MWAIT_EXITING |CPU_BASED_MONITOR_EXITING );
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 28/33 KVM: x86: VMX: Replace some Intel model numbers with mnemonics
In reply to Vitaly KuznetsovFrom: Jim Mattson <[email protected]>
Intel processor code names are more familiar to many readers than their decimal model numbers.
--- arch/x86/kvm/vmx/vmx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
arch/x86/kvm/vmx/vmx.c +5 -5
@@ -2656,11 +2656,11 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,*/ if (boot_cpu_data.x86 ==0x6 ) {switch (boot_cpu_data.x86_model) { -case 26 :/* AAK155 */ -case 30 :/* AAP115 */ -case 37 :/* AAT100 */ -case 44 :/* BC86,AAY89,BD102 */ -case 46 :/* BA97 */ +case INTEL_FAM6_NEHALEM_EP :/* AAK155 */ +case INTEL_FAM6_NEHALEM :/* AAP115 */ +case INTEL_FAM6_WESTMERE :/* AAT100 */ +case INTEL_FAM6_WESTMERE_EP :/* BC86,AAY89,BD102 */ +case INTEL_FAM6_NEHALEM_EX :/* BA97 */ _vmentry_control &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL ; _vmexit_control &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL ; pr_warn_once("kvm: VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL "
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 29/33 KVM: VMX: Move LOAD_IA32_PERF_GLOBAL_CTRL errata handling out of setup_vmcs_config()
In reply to Vitaly KuznetsovAs a preparation to reusing the result of setup_vmcs_config() for setting up nested VMX control MSRs, move LOAD_IA32_PERF_GLOBAL_CTRL errata handling to vmx_vmexit_ctrl()/vmx_vmentry_ctrl() and print the warning from hardware_setup(). While it seems reasonable to not expose LOAD_IA32_PERF_GLOBAL_CTRL controls to L1 hypervisor on buggy CPUs, such change would inevitably break live migration from older KVMs where the controls are exposed. Keep the status quo for now, L1 hypervisor itself is supposed to take care of the errata.
--- arch/x86/kvm/vmx/vmx.c | 59 +++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 24 deletions(-)
arch/x86/kvm/vmx/vmx.c +35 -24
@@ -2493,6 +2493,30 @@ static bool cpu_has_sgx(void)return cpuid_eax (0 ) >=0x12 && (cpuid_eax (0x12 ) &BIT (0 )); } +/* +* Some cpus support VM_{ENTRY,EXIT}_IA32_PERF_GLOBAL_CTRL but they +* can't be used due to errata where VM Exit may incorrectly clear +* IA32_PERF_GLOBAL_CTRL[34:32]. Work around the errata by using the +* MSR load mechanism to switch IA32_PERF_GLOBAL_CTRL. +*/ +static bool cpu_has_perf_global_ctrl_bug (void ) +{ +if (boot_cpu_data.x86 ==0x6 ) { +switch (boot_cpu_data.x86_model) { +case INTEL_FAM6_NEHALEM_EP :/* AAK155 */ +case INTEL_FAM6_NEHALEM :/* AAP115 */ +case INTEL_FAM6_WESTMERE :/* AAT100 */ +case INTEL_FAM6_WESTMERE_EP :/* BC86,AAY89,BD102 */ +case INTEL_FAM6_NEHALEM_EX :/* BA97 */ +return true; +default : +break ; + } + } + +return false; +} +static __init int adjust_vmx_controls (u32 ctl_min,u32 ctl_opt,u32 msr,u32 *result) {
@@ -2648,30 +2672,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, _vmexit_control &= ~x_ctrl; } -/* -* Some cpus support VM_{ENTRY,EXIT}_IA32_PERF_GLOBAL_CTRL but they -* can't be used due to an errata where VM Exit may incorrectly clear -* IA32_PERF_GLOBAL_CTRL[34:32]. Workaround the errata by using the -* MSR load mechanism to switch IA32_PERF_GLOBAL_CTRL. -*/ -if (boot_cpu_data.x86 ==0x6 ) { -switch (boot_cpu_data.x86_model) { -case INTEL_FAM6_NEHALEM_EP :/* AAK155 */ -case INTEL_FAM6_NEHALEM :/* AAP115 */ -case INTEL_FAM6_WESTMERE :/* AAT100 */ -case INTEL_FAM6_WESTMERE_EP :/* BC86,AAY89,BD102 */ -case INTEL_FAM6_NEHALEM_EX :/* BA97 */ - _vmentry_control &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL ; - _vmexit_control &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL ; -pr_warn_once ("kvm: VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL " -"does not work properly. Using workaround\n" ); -break ; -default : -break ; - } - } - -rdmsr (MSR_IA32_VMX_BASIC , vmx_msr_low, vmx_msr_high);/* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
@@ -4267,6 +4267,9 @@ static u32 vmx_vmentry_ctrl(void)VM_ENTRY_LOAD_IA32_EFER | VM_ENTRY_IA32E_MODE); +if (cpu_has_perf_global_ctrl_bug ()) + vmentry_ctrl &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL ; +return vmentry_ctrl; }
@@ -4284,6 +4287,10 @@ static u32 vmx_vmexit_ctrl(void)if (vmx_pt_mode_is_system ()) vmexit_ctrl &= ~(VM_EXIT_PT_CONCEAL_PIP |VM_EXIT_CLEAR_IA32_RTIT_CTL ); + +if (cpu_has_perf_global_ctrl_bug ()) + vmexit_ctrl &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL ; +/* Loading of EFER and PERF_GLOBAL_CTRL are toggled dynamically */ return vmexit_ctrl & ~(VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |VM_EXIT_LOAD_IA32_EFER );
@@ -8190,6 +8197,10 @@ static __init int hardware_setup(void)if (setup_vmcs_config (&vmcs_config, &vmx_capability) <0 )return -EIO ; +if (cpu_has_perf_global_ctrl_bug ()) +pr_warn_once ("kvm: VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL " +"does not work properly. Using workaround\n" ); +if (boot_cpu_has (X86_FEATURE_NX ))kvm_enable_efer_bits (EFER_NX );
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 30/33 KVM: nVMX: Always set required-1 bits of pinbased_ctls to PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR
In reply to Vitaly KuznetsovSimilar to exit_ctls_low, entry_ctls_low, procbased_ctls_low, pinbased_ctls_low should be set to PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR and not host's MSR_IA32_VMX_PINBASED_CTLS value |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR.
The commit eabeaaccfca0 ("KVM: nVMX: Clean up and fix pin-based execution controls") which introduced '|=' doesn't mention anything about why this is needed, the change seems rather accidental.
Note: normally, required-1 portion of MSR_IA32_VMX_PINBASED_CTLS should be equal to PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR so no behavioral change is expected, however, it is (in theory) possible to observe something different there when e.g. KVM is running as a nested hypervisor. Hope this doesn't happen in practice.
--- arch/x86/kvm/vmx/nested.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/vmx/nested.c +1 -1
@@ -6579,7 +6579,7 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)rdmsr (MSR_IA32_VMX_PINBASED_CTLS , msrs->pinbased_ctls_low, msrs->pinbased_ctls_high); - msrs->pinbased_ctls_low |= + msrs->pinbased_ctls_low =PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR ; msrs->pinbased_ctls_high &= PIN_BASED_EXT_INTR_MASK |
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 31/33 KVM: nVMX: Use sanitized allowed-1 bits for VMX control MSRs
In reply to Vitaly KuznetsovUsing raw host MSR values for setting up nested VMX control MSRs is incorrect as some features need to disabled, e.g. when KVM runs as a nested hypervisor on Hyper-V and uses Enlightened VMCS or when a workaround for IA32_PERF_GLOBAL_CTRL is applied. For non-nested VMX, this is done in setup_vmcs_config() and the result is stored in vmcs_config. Use it for setting up allowed-1 bits in nested VMX MSRs too.
--- arch/x86/kvm/vmx/nested.c | 30 ++++++++++++------------------ arch/x86/kvm/vmx/nested.h | 2 +- arch/x86/kvm/vmx/vmx.c | 5 ++--- 3 files changed, 15 insertions(+), 22 deletions(-)
arch/x86/kvm/vmx/nested.c +12 -18
@@ -6558,8 +6558,10 @@ static u64 nested_vmx_calc_vmcs_enum_msr(void)* bit in the high half is on if the corresponding bit in the control field * may be on. See also vmx_control_verify(). */ -void nested_vmx_setup_ctls_msrs (struct nested_vmx_msrs *msrs,u32 ept_caps) +void nested_vmx_setup_ctls_msrs (struct vmcs_config *vmcs_conf,u32 ept_caps) { +struct nested_vmx_msrs *msrs = &vmcs_conf->nested; +/* * Note that as a general rule, the high half of the MSRs (bits in * the control fields which may be 1) should be initialized by the
@@ -6576,11 +6578,10 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)*/ /* pin-based controls */ -rdmsr (MSR_IA32_VMX_PINBASED_CTLS , - msrs->pinbased_ctls_low, - msrs->pinbased_ctls_high); msrs->pinbased_ctls_low =PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR ; + + msrs->pinbased_ctls_high = vmcs_conf->pin_based_exec_ctrl; msrs->pinbased_ctls_high &=PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING |
@@ -6591,12 +6592,10 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)PIN_BASED_VMX_PREEMPTION_TIMER ;/* exit controls */ -rdmsr (MSR_IA32_VMX_EXIT_CTLS , - msrs->exit_ctls_low, - msrs->exit_ctls_high); msrs->exit_ctls_low =VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR ; + msrs->exit_ctls_high = vmcs_conf->vmexit_ctrl; msrs->exit_ctls_high &=#ifdef CONFIG_X86_64 VM_EXIT_HOST_ADDR_SPACE_SIZE |
@@ -6613,11 +6612,10 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps) msrs->exit_ctls_low &= ~VM_EXIT_SAVE_DEBUG_CONTROLS ;/* entry controls */ -rdmsr (MSR_IA32_VMX_ENTRY_CTLS , - msrs->entry_ctls_low, - msrs->entry_ctls_high); msrs->entry_ctls_low =VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR ; + + msrs->entry_ctls_high = vmcs_conf->vmentry_ctrl; msrs->entry_ctls_high &=#ifdef CONFIG_X86_64 VM_ENTRY_IA32E_MODE |
@@ -6631,11 +6629,10 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps) msrs->entry_ctls_low &= ~VM_ENTRY_LOAD_DEBUG_CONTROLS ;/* cpu-based controls */ -rdmsr (MSR_IA32_VMX_PROCBASED_CTLS , - msrs->procbased_ctls_low, - msrs->procbased_ctls_high); msrs->procbased_ctls_low =CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR ; + + msrs->procbased_ctls_high = vmcs_conf->cpu_based_exec_ctrl; msrs->procbased_ctls_high &=CPU_BASED_INTR_WINDOW_EXITING | CPU_BASED_NMI_WINDOW_EXITING | CPU_BASED_USE_TSC_OFFSETTING |
@@ -6669,12 +6666,9 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)* depend on CPUID bits, they are added later by * vmx_vcpu_after_set_cpuid. */ -if (msrs->procbased_ctls_high &CPU_BASED_ACTIVATE_SECONDARY_CONTROLS ) -rdmsr (MSR_IA32_VMX_PROCBASED_CTLS2 , - msrs->secondary_ctls_low, - msrs->secondary_ctls_high); - msrs->secondary_ctls_low =0 ; + + msrs->secondary_ctls_high = vmcs_conf->cpu_based_2nd_exec_ctrl; msrs->secondary_ctls_high &=SECONDARY_EXEC_DESC | SECONDARY_EXEC_ENABLE_RDTSCP |
arch/x86/kvm/vmx/nested.h +1 -1
@@ -17,7 +17,7 @@ enum nvmx_vmentry_status { };void vmx_leave_nested (struct kvm_vcpu *vcpu); -void nested_vmx_setup_ctls_msrs (struct nested_vmx_msrs *msrs,u32 ept_caps); +void nested_vmx_setup_ctls_msrs (struct vmcs_config *vmcs_conf,u32 ept_caps);void nested_vmx_hardware_unsetup (void );__init int nested_vmx_hardware_setup (int (*exit_handlers[])(struct kvm_vcpu *));void nested_vmx_set_vmcs_shadowing_bitmap (void );
arch/x86/kvm/vmx/vmx.c +2 -3
@@ -7400,7 +7400,7 @@ static int __init vmx_check_processor_compat(void)if (setup_vmcs_config (&vmcs_conf, &vmx_cap) <0 )return -EIO ;if (nested) -nested_vmx_setup_ctls_msrs (&vmcs_conf.nested, vmx_cap.ept); +nested_vmx_setup_ctls_msrs (&vmcs_conf, vmx_cap.ept);if (memcmp (&vmcs_config, &vmcs_conf,sizeof (struct vmcs_config )) !=0 ) {printk (KERN_ERR "kvm: CPU %d feature inconsistency!\n" ,smp_processor_id ());
@@ -8355,8 +8355,7 @@ static __init int hardware_setup(void)setup_default_sgx_lepubkeyhash ();if (nested) { -nested_vmx_setup_ctls_msrs (&vmcs_config.nested, - vmx_capability.ept); +nested_vmx_setup_ctls_msrs (&vmcs_config, vmx_capability.ept); r =nested_vmx_hardware_setup (kvm_vmx_exit_handlers);if (r)
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 32/33 KVM: VMX: Cache MSR_IA32_VMX_MISC in vmcs_config
In reply to Vitaly KuznetsovLike other host VMX control MSRs, MSR_IA32_VMX_MISC can be cached in vmcs_config to avoid the need to re-read it later, e.g. from cpu_has_vmx_intel_pt() or cpu_has_vmx_shadow_vmcs().
No (real) functional change intended.
--- arch/x86/kvm/vmx/capabilities.h | 11 +++-------- arch/x86/kvm/vmx/vmx.c | 8 +++++--- 2 files changed, 8 insertions(+), 11 deletions(-)
arch/x86/kvm/vmx/capabilities.h +3 -8
@@ -65,6 +65,7 @@ struct vmcs_config {u64 cpu_based_3rd_exec_ctrl;u32 vmexit_ctrl;u32 vmentry_ctrl; +u64 misc;struct nested_vmx_msrs nested; };extern struct vmcs_config vmcs_config;
@@ -225,11 +226,8 @@ static inline bool cpu_has_vmx_vmfunc(void)static inline bool cpu_has_vmx_shadow_vmcs (void ) { -u64 vmx_msr; -/* check if the cpu supports writing r/o exit information fields */ -rdmsrl (MSR_IA32_VMX_MISC , vmx_msr); -if (!(vmx_msr &MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS )) +if (!(vmcs_config.misc &MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS ))return false; return vmcs_config.cpu_based_2nd_exec_ctrl &
@@ -371,10 +369,7 @@ static inline bool cpu_has_vmx_invvpid_global(void)static inline bool cpu_has_vmx_intel_pt (void ) { -u64 vmx_msr; - -rdmsrl (MSR_IA32_VMX_MISC , vmx_msr); -return (vmx_msr &MSR_IA32_VMX_MISC_INTEL_PT ) && +return (vmcs_config.misc &MSR_IA32_VMX_MISC_INTEL_PT ) && (vmcs_config.cpu_based_2nd_exec_ctrl &SECONDARY_EXEC_PT_USE_GPA ) && (vmcs_config.vmentry_ctrl &VM_ENTRY_LOAD_IA32_RTIT_CTL ); }
arch/x86/kvm/vmx/vmx.c +5 -3
@@ -2555,6 +2555,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,u64 _cpu_based_3rd_exec_control =0 ;u32 _vmexit_control =0 ;u32 _vmentry_control =0 ; +u64 misc_msr;int i;/*
@@ -2688,6 +2689,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,if (((vmx_msr_high >>18 ) &15 ) !=6 )return -EIO ; +rdmsrl (MSR_IA32_VMX_MISC , misc_msr); + vmcs_conf->size = vmx_msr_high &0x1fff ; vmcs_conf->basic_cap = vmx_msr_high & ~0x1fff ;
@@ -2699,6 +2702,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, vmcs_conf->cpu_based_3rd_exec_ctrl = _cpu_based_3rd_exec_control; vmcs_conf->vmexit_ctrl = _vmexit_control; vmcs_conf->vmentry_ctrl = _vmentry_control; + vmcs_conf->misc = misc_msr;return 0 ; }
@@ -8315,11 +8319,9 @@ static __init int hardware_setup(void)if (enable_preemption_timer) {u64 use_timer_freq =5000ULL *1000 *1000 ; -u64 vmx_msr; -rdmsrl (MSR_IA32_VMX_MISC , vmx_msr); cpu_preemption_timer_multi = - vmx_msr &VMX_MISC_PREEMPTION_TIMER_RATE_MASK ; + vmcs_config.misc &VMX_MISC_PREEMPTION_TIMER_RATE_MASK ;if (tsc_khz) use_timer_freq = (u64 )tsc_khz *1000 ;
Signature · 1 line
2.37.2
Vitaly Kuznetsov
maintainerPATCH v6 33/33 KVM: nVMX: Use cached host MSR_IA32_VMX_MISC value for setting up nested MSR
In reply to Vitaly Kuznetsovvmcs_config has cached host MSR_IA32_VMX_MISC value, use it for setting up nested MSR_IA32_VMX_MISC in nested_vmx_setup_ctls_msrs() and avoid the redundant rdmsr().
No (real) functional change intended.
--- arch/x86/kvm/vmx/nested.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
arch/x86/kvm/vmx/nested.c +1 -4
@@ -6748,10 +6748,7 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) msrs->secondary_ctls_high |=SECONDARY_EXEC_ENCLS_EXITING ;/* miscellaneous data */ -rdmsr (MSR_IA32_VMX_MISC , - msrs->misc_low, - msrs->misc_high); - msrs->misc_low &=VMX_MISC_SAVE_EFER_LMA ; + msrs->misc_low = (u32 )vmcs_conf->misc &VMX_MISC_SAVE_EFER_LMA ; msrs->misc_low |=MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS | VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE |
Signature · 1 line
2.37.2
Quoted 5 lines · Vitaly Kuznetsov
Changes since "[RFC PATCH v6 00/36] KVM: x86: eVMCS rework":
- Drop the most controversialTSC_SCALINGenablement for Hyper-V on KVM:
- "KVM: nVMX: Enforce unsupported eVMCS in VMX MSRs for host accesses" patch dropped.
- "KVM: nVMX: Support TSC scaling with enlightened VMCS" patch dropped.
- "KVM: selftests: Enable TSC scaling in evmcs selftest" patch dropped.
Pushed to branch for_paolo/6.1 at:
https://github.com/sean-jc/linux.git
Unless you hear otherwise, it will make its way to kvm/queue "soon".
Note, the commit IDs are not guaranteed to be stable, and in fact they are guaranteed to not be stable right now as I need to do some surgery.