Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+417
View File
@@ -0,0 +1,417 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_CAPS_H
#define __KVM_X86_VMX_CAPS_H
#include <asm/vmx.h>
#include "../lapic.h"
#include "../x86.h"
#include "../pmu.h"
#include "../cpuid.h"
extern bool __read_mostly enable_vpid;
extern bool __read_mostly flexpriority_enabled;
extern bool __read_mostly enable_ept;
extern bool __read_mostly enable_unrestricted_guest;
extern bool __read_mostly enable_ept_ad_bits;
extern bool __read_mostly enable_cet;
extern bool __read_mostly enable_pml;
extern bool __read_mostly enable_mbec;
extern int __read_mostly pt_mode;
#define PT_MODE_SYSTEM 0
#define PT_MODE_HOST_GUEST 1
struct nested_vmx_msrs {
/*
* We only store the "true" versions of the VMX capability MSRs. We
* generate the "non-true" versions by setting the must-be-1 bits
* according to the SDM.
*/
u32 procbased_ctls_low;
u32 procbased_ctls_high;
u32 secondary_ctls_low;
u32 secondary_ctls_high;
u32 pinbased_ctls_low;
u32 pinbased_ctls_high;
u32 exit_ctls_low;
u32 exit_ctls_high;
u32 entry_ctls_low;
u32 entry_ctls_high;
u32 misc_low;
u32 misc_high;
u32 ept_caps;
u32 vpid_caps;
u64 basic;
u64 cr0_fixed0;
u64 cr0_fixed1;
u64 cr4_fixed0;
u64 cr4_fixed1;
u64 vmcs_enum;
u64 vmfunc_controls;
};
struct vmcs_config {
u64 basic;
u32 pin_based_exec_ctrl;
u32 cpu_based_exec_ctrl;
u32 cpu_based_2nd_exec_ctrl;
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 __ro_after_init;
struct vmx_capability {
u32 ept;
u32 vpid;
};
extern struct vmx_capability vmx_capability __ro_after_init;
static inline bool cpu_has_vmx_basic_inout(void)
{
return vmcs_config.basic & VMX_BASIC_INOUT;
}
static inline bool cpu_has_vmx_basic_no_hw_errcode_cc(void)
{
return vmcs_config.basic & VMX_BASIC_NO_HW_ERROR_CODE_CC;
}
static inline bool cpu_has_virtual_nmis(void)
{
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)
{
return vmcs_config.pin_based_exec_ctrl &
PIN_BASED_VMX_PREEMPTION_TIMER;
}
static inline bool cpu_has_vmx_posted_intr(void)
{
return vmcs_config.pin_based_exec_ctrl & PIN_BASED_POSTED_INTR;
}
static inline bool cpu_has_load_ia32_efer(void)
{
return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_EFER;
}
static inline bool cpu_has_load_perf_global_ctrl(void)
{
return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
}
static inline bool cpu_has_load_cet_ctrl(void)
{
return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_CET_STATE;
}
static inline bool cpu_has_save_perf_global_ctrl(void)
{
return vmcs_config.vmexit_ctrl & VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL;
}
static inline bool cpu_has_vmx_mpx(void)
{
return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_BNDCFGS;
}
static inline bool cpu_has_vmx_tpr_shadow(void)
{
return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW;
}
static inline bool cpu_need_tpr_shadow(struct kvm_vcpu *vcpu)
{
return cpu_has_vmx_tpr_shadow() && lapic_in_kernel(vcpu);
}
static inline bool cpu_has_vmx_msr_bitmap(void)
{
return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS;
}
static inline bool cpu_has_secondary_exec_ctrls(void)
{
return vmcs_config.cpu_based_exec_ctrl &
CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
}
static inline bool cpu_has_tertiary_exec_ctrls(void)
{
return vmcs_config.cpu_based_exec_ctrl &
CPU_BASED_ACTIVATE_TERTIARY_CONTROLS;
}
static inline bool cpu_has_vmx_virtualize_apic_accesses(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
}
static inline bool cpu_has_vmx_ept(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_ENABLE_EPT;
}
static inline bool vmx_umip_emulated(void)
{
return !boot_cpu_has(X86_FEATURE_UMIP) &&
(vmcs_config.cpu_based_2nd_exec_ctrl & SECONDARY_EXEC_DESC);
}
static inline bool cpu_has_vmx_rdtscp(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_ENABLE_RDTSCP;
}
static inline bool cpu_has_vmx_virtualize_x2apic_mode(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
}
static inline bool cpu_has_vmx_vpid(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_ENABLE_VPID;
}
static inline bool cpu_has_vmx_wbinvd_exit(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_WBINVD_EXITING;
}
static inline bool cpu_has_vmx_unrestricted_guest(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_UNRESTRICTED_GUEST;
}
static inline bool cpu_has_vmx_apic_register_virt(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_APIC_REGISTER_VIRT;
}
static inline bool cpu_has_vmx_virtual_intr_delivery(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY;
}
static inline bool cpu_has_vmx_ple(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_PAUSE_LOOP_EXITING;
}
static inline bool cpu_has_vmx_rdrand(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_RDRAND_EXITING;
}
static inline bool cpu_has_vmx_invpcid(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_ENABLE_INVPCID;
}
static inline bool cpu_has_vmx_vmfunc(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_ENABLE_VMFUNC;
}
static inline bool cpu_has_vmx_shadow_vmcs(void)
{
/* check if the cpu supports writing r/o exit information fields */
if (!(vmcs_config.misc & VMX_MISC_VMWRITE_SHADOW_RO_FIELDS))
return false;
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_SHADOW_VMCS;
}
static inline bool cpu_has_vmx_encls_vmexit(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_ENCLS_EXITING;
}
static inline bool cpu_has_vmx_rdseed(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_RDSEED_EXITING;
}
static inline bool cpu_has_vmx_pml(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl & SECONDARY_EXEC_ENABLE_PML;
}
static inline bool cpu_has_vmx_xsaves(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_ENABLE_XSAVES;
}
static inline bool cpu_has_vmx_waitpkg(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
}
static inline bool cpu_has_vmx_tsc_scaling(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_TSC_SCALING;
}
static inline bool cpu_has_vmx_bus_lock_detection(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_BUS_LOCK_DETECTION;
}
static inline bool cpu_has_vmx_apicv(void)
{
return cpu_has_vmx_apic_register_virt() &&
cpu_has_vmx_virtual_intr_delivery() &&
cpu_has_vmx_posted_intr();
}
static inline bool cpu_has_vmx_ipiv(void)
{
return vmcs_config.cpu_based_3rd_exec_ctrl & TERTIARY_EXEC_IPI_VIRT;
}
static inline bool cpu_has_vmx_flexpriority(void)
{
return cpu_has_vmx_tpr_shadow() &&
cpu_has_vmx_virtualize_apic_accesses();
}
static inline bool cpu_has_vmx_ept_4levels(void)
{
return vmx_capability.ept & VMX_EPT_PAGE_WALK_4_BIT;
}
static inline bool cpu_has_vmx_ept_5levels(void)
{
return vmx_capability.ept & VMX_EPT_PAGE_WALK_5_BIT;
}
static inline bool cpu_has_vmx_ept_mt_wb(void)
{
return vmx_capability.ept & VMX_EPTP_WB_BIT;
}
static inline bool cpu_has_vmx_ept_2m_page(void)
{
return vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT;
}
static inline bool cpu_has_vmx_ept_1g_page(void)
{
return vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT;
}
static inline int ept_caps_to_lpage_level(u32 ept_caps)
{
if (ept_caps & VMX_EPT_1GB_PAGE_BIT)
return PG_LEVEL_1G;
if (ept_caps & VMX_EPT_2MB_PAGE_BIT)
return PG_LEVEL_2M;
return PG_LEVEL_4K;
}
static inline bool cpu_has_vmx_ept_ad_bits(void)
{
return vmx_capability.ept & VMX_EPT_AD_BIT;
}
static inline bool cpu_has_vmx_invept_context(void)
{
return vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT;
}
static inline bool cpu_has_vmx_invept_global(void)
{
return vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT;
}
static inline bool cpu_has_vmx_invvpid(void)
{
return vmx_capability.vpid & VMX_VPID_INVVPID_BIT;
}
static inline bool cpu_has_vmx_invvpid_individual_addr(void)
{
return vmx_capability.vpid & VMX_VPID_EXTENT_INDIVIDUAL_ADDR_BIT;
}
static inline bool cpu_has_vmx_invvpid_single(void)
{
return vmx_capability.vpid & VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT;
}
static inline bool cpu_has_vmx_invvpid_global(void)
{
return vmx_capability.vpid & VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
}
static inline bool cpu_has_vmx_intel_pt(void)
{
return (vmcs_config.misc & 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);
}
/*
* Processor Trace can operate in one of three modes:
* a. system-wide: trace both host/guest and output to host buffer
* b. host-only: only trace host and output to host buffer
* c. host-guest: trace host and guest simultaneously and output to their
* respective buffer
*
* KVM currently only supports (a) and (c).
*/
static inline bool vmx_pt_mode_is_system(void)
{
return pt_mode == PT_MODE_SYSTEM;
}
static inline bool vmx_pt_mode_is_host_guest(void)
{
return pt_mode == PT_MODE_HOST_GUEST;
}
static inline bool vmx_pebs_supported(void)
{
return boot_cpu_has(X86_FEATURE_PEBS) && kvm_pmu_cap.pebs_ept &&
!enable_mediated_pmu;
}
static inline bool cpu_has_notify_vmexit(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_NOTIFY_VM_EXITING;
}
static inline bool cpu_has_ept_mbec(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_MODE_BASED_EPT_EXEC;
}
#endif /* __KVM_X86_VMX_CAPS_H */
+188
View File
@@ -0,0 +1,188 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __KVM_X86_VMX_COMMON_H
#define __KVM_X86_VMX_COMMON_H
#include <linux/kvm_host.h>
#include <asm/posted_intr.h>
#include "mmu.h"
union vmx_exit_reason {
struct {
u32 basic : 16;
u32 reserved16 : 1;
u32 reserved17 : 1;
u32 reserved18 : 1;
u32 reserved19 : 1;
u32 reserved20 : 1;
u32 reserved21 : 1;
u32 reserved22 : 1;
u32 reserved23 : 1;
u32 reserved24 : 1;
u32 reserved25 : 1;
u32 bus_lock_detected : 1;
u32 enclave_mode : 1;
u32 smi_pending_mtf : 1;
u32 smi_from_vmx_root : 1;
u32 reserved30 : 1;
u32 failed_vmentry : 1;
};
u32 full;
};
struct vcpu_vt {
/* Posted interrupt descriptor */
struct pi_desc pi_desc;
/* Used if this vCPU is waiting for PI notification wakeup. */
struct list_head pi_wakeup_list;
union vmx_exit_reason exit_reason;
unsigned long exit_qualification;
u32 exit_intr_info;
/*
* If true, guest state has been loaded into hardware, and host state
* saved into vcpu_{vt,vmx,tdx}. If false, host state is loaded into
* hardware.
*/
bool guest_state_loaded;
bool emulation_required;
#ifdef CONFIG_X86_64
u64 msr_host_kernel_gs_base;
#endif
};
#ifdef CONFIG_KVM_INTEL_TDX
static __always_inline bool is_td(struct kvm *kvm)
{
return kvm->arch.vm_type == KVM_X86_TDX_VM;
}
static __always_inline bool is_td_vcpu(struct kvm_vcpu *vcpu)
{
return is_td(vcpu->kvm);
}
#else
static __always_inline bool is_td(struct kvm *kvm) { return false; }
static __always_inline bool is_td_vcpu(struct kvm_vcpu *vcpu) { return false; }
#endif
static inline bool vt_is_tdx_private_gpa(struct kvm *kvm, gpa_t gpa)
{
/* For TDX the direct mask is the shared mask. */
return !kvm_is_addr_direct(kvm, gpa);
}
static inline int __vmx_handle_ept_violation(struct kvm_vcpu *vcpu, gpa_t gpa,
unsigned long exit_qualification)
{
u64 error_code;
/* Is it a write fault? */
error_code = (exit_qualification & EPT_VIOLATION_ACC_WRITE)
? PFERR_WRITE_MASK : 0;
/* Is it a fetch fault? */
error_code |= (exit_qualification & EPT_VIOLATION_ACC_INSTR)
? PFERR_FETCH_MASK : 0;
/* ept page table entry is present? */
error_code |= (exit_qualification &
(EPT_VIOLATION_PROT_MASK & ~EPT_VIOLATION_PROT_USER_EXEC))
? PFERR_PRESENT_MASK : 0;
if (mmu_has_mbec(vcpu->arch.mmu))
error_code |= (exit_qualification & EPT_VIOLATION_PROT_USER_EXEC)
? PFERR_PRESENT_MASK : 0;
if (exit_qualification & EPT_VIOLATION_GVA_IS_VALID) {
if (exit_qualification & EPT_VIOLATION_GVA_TRANSLATED) {
error_code |= PFERR_GUEST_FINAL_MASK;
if (exit_qualification & EPT_VIOLATION_GVA_USER)
error_code |= PFERR_USER_MASK;
} else {
error_code |= PFERR_GUEST_PAGE_MASK;
}
}
if (vt_is_tdx_private_gpa(vcpu->kvm, gpa))
error_code |= PFERR_PRIVATE_ACCESS;
return kvm_mmu_page_fault(vcpu, gpa, error_code, NULL, 0);
}
static inline void kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu,
int pi_vec)
{
#ifdef CONFIG_SMP
if (vcpu->mode == IN_GUEST_MODE) {
/*
* The vector of the virtual has already been set in the PIR.
* Send a notification event to deliver the virtual interrupt
* unless the vCPU is the currently running vCPU, i.e. the
* event is being sent from a fastpath VM-Exit handler, in
* which case the PIR will be synced to the vIRR before
* re-entering the guest.
*
* When the target is not the running vCPU, the following
* possibilities emerge:
*
* Case 1: vCPU stays in non-root mode. Sending a notification
* event posts the interrupt to the vCPU.
*
* Case 2: vCPU exits to root mode and is still runnable. The
* PIR will be synced to the vIRR before re-entering the guest.
* Sending a notification event is ok as the host IRQ handler
* will ignore the spurious event.
*
* Case 3: vCPU exits to root mode and is blocked. vcpu_block()
* has already synced PIR to vIRR and never blocks the vCPU if
* the vIRR is not empty. Therefore, a blocked vCPU here does
* not wait for any requested interrupts in PIR, and sending a
* notification event also results in a benign, spurious event.
*/
if (vcpu != kvm_get_running_vcpu())
__apic_send_IPI_mask(get_cpu_mask(vcpu->cpu), pi_vec);
return;
}
#endif
/*
* The vCPU isn't in the guest; wake the vCPU in case it is blocking,
* otherwise do nothing as KVM will grab the highest priority pending
* IRQ via ->sync_pir_to_irr() in vcpu_enter_guest().
*/
kvm_vcpu_wake_up(vcpu);
}
/*
* Post an interrupt to a vCPU's PIR and trigger the vCPU to process the
* interrupt if necessary.
*/
static inline void __vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu,
struct pi_desc *pi_desc, int vector)
{
if (pi_test_and_set_pir(vector, pi_desc))
return;
/* If a previous notification has sent the IPI, nothing to do. */
if (pi_test_and_set_on(pi_desc))
return;
/*
* The implied barrier in pi_test_and_set_on() pairs with the smp_mb_*()
* after setting vcpu->mode in vcpu_enter_guest(), thus the vCPU is
* guaranteed to see PID.ON=1 and sync the PIR to IRR if triggering a
* posted interrupt "fails" because vcpu->mode != IN_GUEST_MODE.
*/
kvm_vcpu_trigger_posted_interrupt(vcpu, POSTED_INTR_VECTOR);
}
noinstr void vmx_handle_nmi(struct kvm_vcpu *vcpu);
#endif /* __KVM_X86_VMX_COMMON_H */
+230
View File
@@ -0,0 +1,230 @@
// SPDX-License-Identifier: GPL-2.0
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/errno.h>
#include <linux/smp.h>
#include "x86.h"
#include "../cpuid.h"
#include "hyperv.h"
#include "nested.h"
#include "vmcs.h"
#include "vmx.h"
#include "trace.h"
#define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK
u64 nested_get_evmptr(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
if (unlikely(kvm_hv_get_assist_page(vcpu)))
return EVMPTR_INVALID;
if (unlikely(!hv_vcpu->vp_assist_page.enlighten_vmentry))
return EVMPTR_INVALID;
return hv_vcpu->vp_assist_page.current_nested_vmcs;
}
uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu)
{
/*
* vmcs_version represents the range of supported Enlightened VMCS
* 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))
return (KVM_EVMCS_VERSION << 8) | 1;
return 0;
}
enum evmcs_revision {
EVMCSv1_LEGACY,
NR_EVMCS_REVISIONS,
};
enum evmcs_ctrl_type {
EVMCS_EXIT_CTRLS,
EVMCS_ENTRY_CTRLS,
EVMCS_EXEC_CTRL,
EVMCS_2NDEXEC,
EVMCS_3RDEXEC,
EVMCS_PINCTRL,
EVMCS_VMFUNC,
NR_EVMCS_CTRLS,
};
static const u32 evmcs_supported_ctrls[NR_EVMCS_CTRLS][NR_EVMCS_REVISIONS] = {
[EVMCS_EXIT_CTRLS] = {
[EVMCSv1_LEGACY] = EVMCS1_SUPPORTED_VMEXIT_CTRL,
},
[EVMCS_ENTRY_CTRLS] = {
[EVMCSv1_LEGACY] = EVMCS1_SUPPORTED_VMENTRY_CTRL,
},
[EVMCS_EXEC_CTRL] = {
[EVMCSv1_LEGACY] = EVMCS1_SUPPORTED_EXEC_CTRL,
},
[EVMCS_2NDEXEC] = {
[EVMCSv1_LEGACY] = EVMCS1_SUPPORTED_2NDEXEC & ~SECONDARY_EXEC_TSC_SCALING,
},
[EVMCS_3RDEXEC] = {
[EVMCSv1_LEGACY] = EVMCS1_SUPPORTED_3RDEXEC,
},
[EVMCS_PINCTRL] = {
[EVMCSv1_LEGACY] = EVMCS1_SUPPORTED_PINCTRL,
},
[EVMCS_VMFUNC] = {
[EVMCSv1_LEGACY] = EVMCS1_SUPPORTED_VMFUNC,
},
};
static u32 evmcs_get_supported_ctls(enum evmcs_ctrl_type ctrl_type)
{
enum evmcs_revision evmcs_rev = EVMCSv1_LEGACY;
return evmcs_supported_ctrls[ctrl_type][evmcs_rev];
}
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 supported_ctrls;
/*
* Hyper-V 2016 and 2019 try using these features even when eVMCS
* is enabled but there are no corresponding fields.
*/
switch (msr_index) {
case MSR_IA32_VMX_EXIT_CTLS:
case MSR_IA32_VMX_TRUE_EXIT_CTLS:
supported_ctrls = evmcs_get_supported_ctls(EVMCS_EXIT_CTRLS);
if (!evmcs_has_perf_global_ctrl(vcpu))
supported_ctrls &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL;
ctl_high &= supported_ctrls;
break;
case MSR_IA32_VMX_ENTRY_CTLS:
case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
supported_ctrls = evmcs_get_supported_ctls(EVMCS_ENTRY_CTRLS);
if (!evmcs_has_perf_global_ctrl(vcpu))
supported_ctrls &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
ctl_high &= supported_ctrls;
break;
case MSR_IA32_VMX_PROCBASED_CTLS:
case MSR_IA32_VMX_TRUE_PROCBASED_CTLS:
ctl_high &= evmcs_get_supported_ctls(EVMCS_EXEC_CTRL);
break;
case MSR_IA32_VMX_PROCBASED_CTLS2:
ctl_high &= evmcs_get_supported_ctls(EVMCS_2NDEXEC);
break;
case MSR_IA32_VMX_TRUE_PINBASED_CTLS:
case MSR_IA32_VMX_PINBASED_CTLS:
ctl_high &= evmcs_get_supported_ctls(EVMCS_PINCTRL);
break;
case MSR_IA32_VMX_VMFUNC:
ctl_low &= evmcs_get_supported_ctls(EVMCS_VMFUNC);
break;
}
*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_supported_ctls(ctrl_type));
}
int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
{
if (CC(!nested_evmcs_is_valid_controls(EVMCS_PINCTRL,
vmcs12->pin_based_vm_exec_control)))
return -EINVAL;
if (CC(!nested_evmcs_is_valid_controls(EVMCS_EXEC_CTRL,
vmcs12->cpu_based_vm_exec_control)))
return -EINVAL;
if (CC(!nested_evmcs_is_valid_controls(EVMCS_2NDEXEC,
vmcs12->secondary_vm_exec_control)))
return -EINVAL;
if (CC(!nested_evmcs_is_valid_controls(EVMCS_EXIT_CTRLS,
vmcs12->vm_exit_controls)))
return -EINVAL;
if (CC(!nested_evmcs_is_valid_controls(EVMCS_ENTRY_CTRLS,
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;
return 0;
}
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
uint16_t *vmcs_version)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
vmx->nested.enlightened_vmcs_enabled = true;
if (vmcs_version)
*vmcs_version = nested_get_evmcs_version(vcpu);
return 0;
}
bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
struct vcpu_vmx *vmx = to_vmx(vcpu);
struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
if (!hv_vcpu || !evmcs)
return false;
if (!evmcs->hv_enlightenments_control.nested_flush_hypercall)
return false;
return hv_vcpu->vp_assist_page.nested_control.features.directhypercall;
}
void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu)
{
nested_vmx_vmexit(vcpu, HV_VMX_SYNTHETIC_EXIT_REASON_TRAP_AFTER_FLUSH, 0, 0);
}
+90
View File
@@ -0,0 +1,90 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_HYPERV_H
#define __KVM_X86_VMX_HYPERV_H
#include <linux/kvm_host.h>
#include "vmcs12.h"
#include "vmx.h"
#define EVMPTR_INVALID (-1ULL)
#define EVMPTR_MAP_PENDING (-2ULL)
enum nested_evmptrld_status {
EVMPTRLD_DISABLED,
EVMPTRLD_SUCCEEDED,
EVMPTRLD_VMFAIL,
EVMPTRLD_ERROR,
};
#ifdef CONFIG_KVM_HYPERV
static inline bool evmptr_is_valid(u64 evmptr)
{
return evmptr != EVMPTR_INVALID && evmptr != EVMPTR_MAP_PENDING;
}
static inline bool nested_vmx_is_evmptr12_valid(struct vcpu_vmx *vmx)
{
return evmptr_is_valid(vmx->nested.hv_evmcs_vmptr);
}
static inline bool evmptr_is_set(u64 evmptr)
{
return evmptr != EVMPTR_INVALID;
}
static inline bool nested_vmx_is_evmptr12_set(struct vcpu_vmx *vmx)
{
return evmptr_is_set(vmx->nested.hv_evmcs_vmptr);
}
static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
{
return vmx->nested.hv_evmcs;
}
static inline bool guest_cpu_cap_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;
}
u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
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(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
#else
static inline bool evmptr_is_valid(u64 evmptr)
{
return false;
}
static inline bool nested_vmx_is_evmptr12_valid(struct vcpu_vmx *vmx)
{
return false;
}
static inline bool evmptr_is_set(u64 evmptr)
{
return false;
}
static inline bool nested_vmx_is_evmptr12_set(struct vcpu_vmx *vmx)
{
return false;
}
static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
{
return NULL;
}
#endif
#endif /* __KVM_X86_VMX_HYPERV_H */
+315
View File
@@ -0,0 +1,315 @@
// SPDX-License-Identifier: GPL-2.0
/*
* This file contains common code for working with Enlightened VMCS which is
* used both by Hyper-V on KVM and KVM on Hyper-V.
*/
#include "hyperv_evmcs.h"
#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
#define EVMCS1_FIELD(number, name, clean_field)[ENC_TO_VMCS12_IDX(number)] = \
{EVMCS1_OFFSET(name), clean_field}
const struct evmcs_field vmcs_field_to_evmcs_1[] = {
/* 64 bit rw */
EVMCS1_FIELD(GUEST_RIP, guest_rip,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(GUEST_RSP, guest_rsp,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
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,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_CR4, host_cr4,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_RIP, host_rip,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
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,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
EVMCS1_FIELD(GUEST_CR0, guest_cr0,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
EVMCS1_FIELD(GUEST_CR3, guest_cr3,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
EVMCS1_FIELD(GUEST_CR4, guest_cr4,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
EVMCS1_FIELD(GUEST_DR7, guest_dr7,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
EVMCS1_FIELD(HOST_RSP, host_rsp,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
EVMCS1_FIELD(EPT_POINTER, ept_pointer,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
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,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
/*
* Not defined in KVM:
*
* EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
* EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
* EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
* EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
*/
EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
/*
* No mask defined in the spec as Hyper-V doesn't currently support
* these. Future proof by resetting the whole clean field mask on
* access.
*/
EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
/* 32 bit rw */
EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
vm_entry_exception_error_code,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
/* 32 bit read only */
EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
/* No mask defined in the spec (not used) */
EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
/* 16 bit rw */
EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
};
const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
+167
View File
@@ -0,0 +1,167 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This file contains common definitions for working with Enlightened VMCS which
* are used both by Hyper-V on KVM and KVM on Hyper-V.
*/
#ifndef __KVM_X86_VMX_HYPERV_EVMCS_H
#define __KVM_X86_VMX_HYPERV_EVMCS_H
#include <hyperv/hvhdk.h>
#include "capabilities.h"
#include "vmcs12.h"
#define KVM_EVMCS_VERSION 1
/*
* Enlightened VMCSv1 doesn't support these:
*
* POSTED_INTR_NV = 0x00000002,
* GUEST_INTR_STATUS = 0x00000810,
* APIC_ACCESS_ADDR = 0x00002014,
* POSTED_INTR_DESC_ADDR = 0x00002016,
* EOI_EXIT_BITMAP0 = 0x0000201c,
* EOI_EXIT_BITMAP1 = 0x0000201e,
* EOI_EXIT_BITMAP2 = 0x00002020,
* EOI_EXIT_BITMAP3 = 0x00002022,
* GUEST_PML_INDEX = 0x00000812,
* PML_ADDRESS = 0x0000200e,
* VM_FUNCTION_CONTROL = 0x00002018,
* EPTP_LIST_ADDRESS = 0x00002024,
* VMREAD_BITMAP = 0x00002026,
* VMWRITE_BITMAP = 0x00002028,
*
* TSC_MULTIPLIER = 0x00002032,
* PLE_GAP = 0x00004020,
* PLE_WINDOW = 0x00004022,
* VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
*
* Currently unsupported in KVM:
* GUEST_IA32_RTIT_CTL = 0x00002814,
*/
#define EVMCS1_SUPPORTED_PINCTRL \
(PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
PIN_BASED_EXT_INTR_MASK | \
PIN_BASED_NMI_EXITING | \
PIN_BASED_VIRTUAL_NMIS)
#define EVMCS1_SUPPORTED_EXEC_CTRL \
(CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
CPU_BASED_HLT_EXITING | \
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 | \
CPU_BASED_CR8_LOAD_EXITING | \
CPU_BASED_CR8_STORE_EXITING | \
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)
#define EVMCS1_SUPPORTED_2NDEXEC \
(SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
SECONDARY_EXEC_WBINVD_EXITING | \
SECONDARY_EXEC_ENABLE_VPID | \
SECONDARY_EXEC_ENABLE_EPT | \
SECONDARY_EXEC_UNRESTRICTED_GUEST | \
SECONDARY_EXEC_DESC | \
SECONDARY_EXEC_ENABLE_RDTSCP | \
SECONDARY_EXEC_ENABLE_INVPCID | \
SECONDARY_EXEC_ENABLE_XSAVES | \
SECONDARY_EXEC_RDSEED_EXITING | \
SECONDARY_EXEC_RDRAND_EXITING | \
SECONDARY_EXEC_TSC_SCALING | \
SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
SECONDARY_EXEC_PT_USE_GPA | \
SECONDARY_EXEC_PT_CONCEAL_VMX | \
SECONDARY_EXEC_BUS_LOCK_DETECTION | \
SECONDARY_EXEC_NOTIFY_VM_EXITING | \
SECONDARY_EXEC_MODE_BASED_EPT_EXEC | \
SECONDARY_EXEC_ENCLS_EXITING)
#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
(VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
VM_EXIT_SAVE_DEBUG_CONTROLS | \
VM_EXIT_ACK_INTR_ON_EXIT | \
VM_EXIT_HOST_ADDR_SPACE_SIZE | \
VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
VM_EXIT_SAVE_IA32_PAT | \
VM_EXIT_LOAD_IA32_PAT | \
VM_EXIT_SAVE_IA32_EFER | \
VM_EXIT_LOAD_IA32_EFER | \
VM_EXIT_CLEAR_BNDCFGS | \
VM_EXIT_PT_CONCEAL_PIP | \
VM_EXIT_CLEAR_IA32_RTIT_CTL)
#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
(VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
VM_ENTRY_LOAD_DEBUG_CONTROLS | \
VM_ENTRY_IA32E_MODE | \
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)
#define EVMCS1_SUPPORTED_VMFUNC (0)
struct evmcs_field {
u16 offset;
u16 clean_field;
};
extern const struct evmcs_field vmcs_field_to_evmcs_1[];
extern const unsigned int nr_evmcs_1_fields;
static __always_inline int evmcs_field_offset(unsigned long field,
u16 *clean_field)
{
const struct evmcs_field *evmcs_field;
unsigned int index = ENC_TO_VMCS12_IDX(field);
if (unlikely(index >= nr_evmcs_1_fields))
return -ENOENT;
evmcs_field = &vmcs_field_to_evmcs_1[index];
/*
* Use offset=0 to detect holes in eVMCS. This offset belongs to
* 'revision_id' but this field has no encoding and is supposed to
* be accessed directly.
*/
if (unlikely(!evmcs_field->offset))
return -ENOENT;
if (clean_field)
*clean_field = evmcs_field->clean_field;
return evmcs_field->offset;
}
static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
unsigned long field, u16 offset)
{
/*
* vmcs12_read_any() doesn't care whether the supplied structure
* is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
* the exact offset of the required field, use it for convenience
* here.
*/
return vmcs12_read_any((void *)evmcs, field, offset);
}
#endif /* __KVM_X86_VMX_HYPERV_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+323
View File
@@ -0,0 +1,323 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_NESTED_H
#define __KVM_X86_VMX_NESTED_H
#include "regs.h"
#include "hyperv.h"
#include "vmcs12.h"
#include "vmx.h"
/*
* Status returned by nested_vmx_enter_non_root_mode():
*/
enum nvmx_vmentry_status {
NVMX_VMENTRY_SUCCESS, /* Entered VMX non-root mode */
NVMX_VMENTRY_VMFAIL, /* Consistency check VMFail */
NVMX_VMENTRY_VMEXIT, /* Consistency check VMExit */
NVMX_VMENTRY_KVM_INTERNAL_ERROR,/* KVM internal error */
};
void vmx_leave_nested(struct kvm_vcpu *vcpu);
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);
int nested_vmx_check_restored_vmcs12(struct kvm_vcpu *vcpu);
void nested_vmx_free_vcpu(struct kvm_vcpu *vcpu);
enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
bool from_vmentry);
bool nested_vmx_reflect_vmexit(struct kvm_vcpu *vcpu);
void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
u32 exit_intr_info, unsigned long exit_qualification,
u32 exit_insn_len);
static inline void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
u32 exit_intr_info,
unsigned long exit_qualification)
{
u32 exit_insn_len;
if (to_vmx(vcpu)->fail || vm_exit_reason == -1 ||
(vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY))
exit_insn_len = 0;
else
exit_insn_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
__nested_vmx_vmexit(vcpu, vm_exit_reason, exit_intr_info,
exit_qualification, exit_insn_len);
}
void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu);
int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, u32 msr_index, u64 *pdata);
int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
u32 vmx_instruction_info, bool wr, int len, gva_t *ret);
bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
int size);
static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
{
lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
!refcount_read(&vcpu->kvm->users_count));
return to_vmx(vcpu)->nested.cached_vmcs12;
}
static inline struct vmcs12 *get_shadow_vmcs12(struct kvm_vcpu *vcpu)
{
lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
!refcount_read(&vcpu->kvm->users_count));
return to_vmx(vcpu)->nested.cached_shadow_vmcs12;
}
/*
* Note: the same condition is checked against the state provided by userspace
* in vmx_set_nested_state; if it is satisfied, the nested state must include
* the VMCS12.
*/
static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
/* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
return vmx->nested.current_vmptr != -1ull ||
nested_vmx_is_evmptr12_set(vmx);
}
static inline u16 nested_get_vpid02(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
return vmx->nested.vpid02 ? vmx->nested.vpid02 : vmx->vpid;
}
static inline unsigned long nested_ept_get_eptp(struct kvm_vcpu *vcpu)
{
/* return the page table to be shadowed - in our case, EPT12 */
return get_vmcs12(vcpu)->ept_pointer;
}
static inline bool nested_ept_ad_enabled(struct kvm_vcpu *vcpu)
{
return nested_ept_get_eptp(vcpu) & VMX_EPTP_AD_ENABLE_BIT;
}
/*
* Return the cr0/4 value that a nested guest would read. This is a combination
* of L1's "real" cr0 used to run the guest (guest_cr0), and the bits shadowed
* by the L1 hypervisor (cr0_read_shadow). KVM must emulate CPU behavior as
* the value+mask loaded into vmcs02 may not match the vmcs12 fields.
*/
static inline unsigned long nested_read_cr0(struct vmcs12 *fields)
{
return (fields->guest_cr0 & ~fields->cr0_guest_host_mask) |
(fields->cr0_read_shadow & fields->cr0_guest_host_mask);
}
static inline unsigned long nested_read_cr4(struct vmcs12 *fields)
{
return (fields->guest_cr4 & ~fields->cr4_guest_host_mask) |
(fields->cr4_read_shadow & fields->cr4_guest_host_mask);
}
static inline unsigned nested_cpu_vmx_misc_cr3_count(struct kvm_vcpu *vcpu)
{
return vmx_misc_cr3_count(to_vmx(vcpu)->nested.msrs.misc_low);
}
/*
* Do the virtual VMX capability MSRs specify that L1 can use VMWRITE
* to modify any valid field of the VMCS, or are the VM-exit
* information fields read-only?
*/
static inline bool nested_cpu_has_vmwrite_any_field(struct kvm_vcpu *vcpu)
{
return to_vmx(vcpu)->nested.msrs.misc_low &
VMX_MISC_VMWRITE_SHADOW_RO_FIELDS;
}
static inline bool nested_cpu_has_zero_length_injection(struct kvm_vcpu *vcpu)
{
return to_vmx(vcpu)->nested.msrs.misc_low & VMX_MISC_ZERO_LEN_INS;
}
static inline bool nested_cpu_supports_monitor_trap_flag(struct kvm_vcpu *vcpu)
{
return to_vmx(vcpu)->nested.msrs.procbased_ctls_high &
CPU_BASED_MONITOR_TRAP_FLAG;
}
static inline bool nested_cpu_has_vmx_shadow_vmcs(struct kvm_vcpu *vcpu)
{
return to_vmx(vcpu)->nested.msrs.secondary_ctls_high &
SECONDARY_EXEC_SHADOW_VMCS;
}
static inline bool nested_cpu_has(struct vmcs12 *vmcs12, u32 bit)
{
return vmcs12->cpu_based_vm_exec_control & bit;
}
static inline bool nested_cpu_has2(struct vmcs12 *vmcs12, u32 bit)
{
return (vmcs12->cpu_based_vm_exec_control &
CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) &&
(vmcs12->secondary_vm_exec_control & bit);
}
static inline bool nested_cpu_has_preemption_timer(struct vmcs12 *vmcs12)
{
return vmcs12->pin_based_vm_exec_control &
PIN_BASED_VMX_PREEMPTION_TIMER;
}
static inline bool nested_cpu_has_nmi_exiting(struct vmcs12 *vmcs12)
{
return vmcs12->pin_based_vm_exec_control & PIN_BASED_NMI_EXITING;
}
static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12)
{
return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS;
}
static inline int nested_cpu_has_mtf(struct vmcs12 *vmcs12)
{
return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_TRAP_FLAG);
}
static inline int nested_cpu_has_ept(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_EPT);
}
static inline bool nested_cpu_has_xsaves(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_XSAVES);
}
static inline bool nested_cpu_has_pml(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_PML);
}
static inline bool nested_cpu_has_virt_x2apic_mode(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE);
}
static inline bool nested_cpu_has_vpid(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_VPID);
}
static inline bool nested_cpu_has_apic_reg_virt(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_APIC_REGISTER_VIRT);
}
static inline bool nested_cpu_has_vid(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
}
static inline bool nested_cpu_has_posted_intr(struct vmcs12 *vmcs12)
{
return vmcs12->pin_based_vm_exec_control & PIN_BASED_POSTED_INTR;
}
static inline bool nested_cpu_has_vmfunc(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_VMFUNC);
}
static inline bool nested_cpu_has_eptp_switching(struct vmcs12 *vmcs12)
{
return nested_cpu_has_vmfunc(vmcs12) &&
(vmcs12->vm_function_control &
VMX_VMFUNC_EPTP_SWITCHING);
}
static inline bool nested_cpu_has_shadow_vmcs(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_SHADOW_VMCS);
}
static inline bool nested_cpu_has_save_preemption_timer(struct vmcs12 *vmcs12)
{
return vmcs12->vm_exit_controls &
VM_EXIT_SAVE_VMX_PREEMPTION_TIMER;
}
static inline bool nested_exit_on_nmi(struct kvm_vcpu *vcpu)
{
return nested_cpu_has_nmi_exiting(get_vmcs12(vcpu));
}
/*
* In nested virtualization, check if L1 asked to exit on external interrupts.
* For most existing hypervisors, this will always return true.
*/
static inline bool nested_exit_on_intr(struct kvm_vcpu *vcpu)
{
return get_vmcs12(vcpu)->pin_based_vm_exec_control &
PIN_BASED_EXT_INTR_MASK;
}
static inline bool nested_cpu_has_encls_exit(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENCLS_EXITING);
}
/*
* if fixed0[i] == 1: val[i] must be 1
* if fixed1[i] == 0: val[i] must be 0
*/
static inline bool fixed_bits_valid(u64 val, u64 fixed0, u64 fixed1)
{
return ((val & fixed1) | fixed0) == val;
}
static inline bool nested_guest_cr0_valid(struct kvm_vcpu *vcpu, unsigned long val)
{
u64 fixed0 = to_vmx(vcpu)->nested.msrs.cr0_fixed0;
u64 fixed1 = to_vmx(vcpu)->nested.msrs.cr0_fixed1;
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
if (to_vmx(vcpu)->nested.msrs.secondary_ctls_high &
SECONDARY_EXEC_UNRESTRICTED_GUEST &&
nested_cpu_has2(vmcs12, SECONDARY_EXEC_UNRESTRICTED_GUEST))
fixed0 &= ~(X86_CR0_PE | X86_CR0_PG);
return fixed_bits_valid(val, fixed0, fixed1);
}
static inline bool nested_host_cr0_valid(struct kvm_vcpu *vcpu, unsigned long val)
{
u64 fixed0 = to_vmx(vcpu)->nested.msrs.cr0_fixed0;
u64 fixed1 = to_vmx(vcpu)->nested.msrs.cr0_fixed1;
return fixed_bits_valid(val, fixed0, fixed1);
}
static inline bool nested_cr4_valid(struct kvm_vcpu *vcpu, unsigned long val)
{
u64 fixed0 = to_vmx(vcpu)->nested.msrs.cr4_fixed0;
u64 fixed1 = to_vmx(vcpu)->nested.msrs.cr4_fixed1;
return fixed_bits_valid(val, fixed0, fixed1) &&
__kvm_is_valid_cr4(vcpu, val);
}
static inline bool nested_cpu_has_no_hw_errcode_cc(struct kvm_vcpu *vcpu)
{
return to_vmx(vcpu)->nested.msrs.basic & VMX_BASIC_NO_HW_ERROR_CODE_CC;
}
/* No difference in the restrictions on guest and host CR4 in VMX operation. */
#define nested_guest_cr4_valid nested_cr4_valid
#define nested_host_cr4_valid nested_cr4_valid
extern struct kvm_x86_nested_ops vmx_nested_ops;
#endif /* __KVM_X86_VMX_NESTED_H */
+861
View File
@@ -0,0 +1,861 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* KVM PMU support for Intel CPUs
*
* Copyright 2011 Red Hat, Inc. and/or its affiliates.
*
* Authors:
* Avi Kivity <avi@redhat.com>
* Gleb Natapov <gleb@redhat.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/kvm_host.h>
#include <linux/perf_event.h>
#include <asm/msr.h>
#include <asm/perf_event.h>
#include <asm/cpuid/api.h>
#include "x86.h"
#include "cpuid.h"
#include "lapic.h"
#include "nested.h"
#include "pmu.h"
#include "tdx.h"
/*
* Perf's "BASE" is wildly misleading, architectural PMUs use bits 31:16 of ECX
* to encode the "type" of counter to read, i.e. this is not a "base". And to
* further confuse things, non-architectural PMUs use bit 31 as a flag for
* "fast" reads, whereas the "type" is an explicit value.
*/
#define INTEL_RDPMC_GP 0
#define INTEL_RDPMC_FIXED INTEL_PMC_FIXED_RDPMC_BASE
#define INTEL_RDPMC_TYPE_MASK GENMASK(31, 16)
#define INTEL_RDPMC_INDEX_MASK GENMASK(15, 0)
#define MSR_PMC_FULL_WIDTH_BIT (MSR_IA32_PMC0 - MSR_IA32_PERFCTR0)
static struct lbr_desc *vcpu_to_lbr_desc(struct kvm_vcpu *vcpu)
{
if (is_td_vcpu(vcpu))
return NULL;
return &to_vmx(vcpu)->lbr_desc;
}
static struct x86_pmu_lbr *vcpu_to_lbr_records(struct kvm_vcpu *vcpu)
{
if (is_td_vcpu(vcpu))
return NULL;
return &to_vmx(vcpu)->lbr_desc.records;
}
#pragma GCC poison to_vmx
static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
{
/*
* Compare against the value the mediated PMU shoves into hardware, not
* the guest's desired value. For the emulated PMU (proxied via perf),
* they are one and the same (fixed_ctr_ctrl_hw isn't used other than
* here). For the mediated PMU, KVM needs to reprogram the actual MSR,
* and so needs to react to potential changes in the value shoved into
* hardware, e.g. to ensure the event filter is enforced.
*/
u64 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl_hw;
struct kvm_pmc *pmc;
int i;
pmu->fixed_ctr_ctrl = data;
pmu->fixed_ctr_ctrl_hw = data;
for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
u8 new_ctrl = fixed_ctrl_field(data, i);
u8 old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i);
if (old_ctrl == new_ctrl)
continue;
pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i);
__set_bit(KVM_FIXED_PMC_BASE_IDX + i, pmu->pmc_in_use);
kvm_pmu_request_counter_reprogram(pmc);
}
}
static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu,
unsigned int idx, u64 *mask)
{
unsigned int type = idx & INTEL_RDPMC_TYPE_MASK;
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct kvm_pmc *counters;
unsigned int num_counters;
u64 bitmask;
/*
* The encoding of ECX for RDPMC is different for architectural versus
* non-architecturals PMUs (PMUs with version '0'). For architectural
* PMUs, bits 31:16 specify the PMC type and bits 15:0 specify the PMC
* index. For non-architectural PMUs, bit 31 is a "fast" flag, and
* bits 30:0 specify the PMC index.
*
* Yell and reject attempts to read PMCs for a non-architectural PMU,
* as KVM doesn't support such PMUs.
*/
if (WARN_ON_ONCE(!pmu->version))
return NULL;
/*
* General Purpose (GP) PMCs are supported on all PMUs, and fixed PMCs
* are supported on all architectural PMUs, i.e. on all virtual PMUs
* supported by KVM. Note, KVM only emulates fixed PMCs for PMU v2+,
* but the type itself is still valid, i.e. let RDPMC fail due to
* accessing a non-existent counter. Reject attempts to read all other
* types, which are unknown/unsupported.
*/
switch (type) {
case INTEL_RDPMC_FIXED:
counters = pmu->fixed_counters;
num_counters = pmu->nr_arch_fixed_counters;
bitmask = pmu->counter_bitmask[KVM_PMC_FIXED];
break;
case INTEL_RDPMC_GP:
counters = pmu->gp_counters;
num_counters = pmu->nr_arch_gp_counters;
bitmask = pmu->counter_bitmask[KVM_PMC_GP];
break;
default:
return NULL;
}
idx &= INTEL_RDPMC_INDEX_MASK;
if (idx >= num_counters)
return NULL;
*mask &= bitmask;
return &counters[array_index_nospec(idx, num_counters)];
}
static inline struct kvm_pmc *get_fw_gp_pmc(struct kvm_pmu *pmu, u32 msr)
{
if (!fw_writes_is_enabled(pmu_to_vcpu(pmu)))
return NULL;
return get_gp_pmc(pmu, msr, MSR_IA32_PMC0);
}
static bool intel_pmu_lbr_is_compatible(struct kvm_vcpu *vcpu)
{
if (is_td_vcpu(vcpu))
return false;
return cpuid_model_is_consistent(vcpu);
}
bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu)
{
if (is_td_vcpu(vcpu))
return false;
return !!vcpu_to_lbr_records(vcpu)->nr;
}
static bool intel_pmu_is_valid_lbr_msr(struct kvm_vcpu *vcpu, u32 index)
{
struct x86_pmu_lbr *records = vcpu_to_lbr_records(vcpu);
bool ret = false;
if (!intel_pmu_lbr_is_enabled(vcpu))
return ret;
ret = (index == MSR_LBR_SELECT) || (index == MSR_LBR_TOS) ||
(index >= records->from && index < records->from + records->nr) ||
(index >= records->to && index < records->to + records->nr);
if (!ret && records->info)
ret = (index >= records->info && index < records->info + records->nr);
return ret;
}
static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
u64 perf_capabilities;
int ret;
switch (msr) {
case MSR_CORE_PERF_FIXED_CTR_CTRL:
return kvm_pmu_has_perf_global_ctrl(pmu);
case MSR_IA32_PEBS_ENABLE:
ret = vcpu_get_perf_capabilities(vcpu) & PERF_CAP_PEBS_FORMAT;
break;
case MSR_IA32_DS_AREA:
ret = guest_cpu_cap_has(vcpu, X86_FEATURE_DS);
break;
case MSR_PEBS_DATA_CFG:
perf_capabilities = vcpu_get_perf_capabilities(vcpu);
ret = (perf_capabilities & PERF_CAP_PEBS_BASELINE) &&
((perf_capabilities & PERF_CAP_PEBS_FORMAT) > 3);
break;
default:
ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) ||
get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0) ||
get_fixed_pmc(pmu, msr) || get_fw_gp_pmc(pmu, msr) ||
intel_pmu_is_valid_lbr_msr(vcpu, msr);
break;
}
return ret;
}
static struct kvm_pmc *intel_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct kvm_pmc *pmc;
pmc = get_fixed_pmc(pmu, msr);
pmc = pmc ? pmc : get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0);
pmc = pmc ? pmc : get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0);
return pmc;
}
static inline void intel_pmu_release_guest_lbr_event(struct kvm_vcpu *vcpu)
{
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
if (!lbr_desc)
return;
if (lbr_desc->event) {
perf_event_release_kernel(lbr_desc->event);
lbr_desc->event = NULL;
vcpu_to_pmu(vcpu)->event_count--;
}
}
int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu)
{
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct perf_event *event;
/*
* The perf_event_attr is constructed in the minimum efficient way:
* - set 'pinned = true' to make it task pinned so that if another
* cpu pinned event reclaims LBR, the event->oncpu will be set to -1;
* - set '.exclude_host = true' to record guest branches behavior;
*
* - set '.config = INTEL_FIXED_VLBR_EVENT' to indicates host perf
* schedule the event without a real HW counter but a fake one;
* check is_guest_lbr_event() and __intel_get_event_constraints();
*
* - set 'sample_type = PERF_SAMPLE_BRANCH_STACK' and
* 'branch_sample_type = PERF_SAMPLE_BRANCH_CALL_STACK |
* PERF_SAMPLE_BRANCH_USER' to configure it as a LBR callstack
* event, which helps KVM to save/restore guest LBR records
* during host context switches and reduces quite a lot overhead,
* check branch_user_callstack() and intel_pmu_lbr_sched_task();
*/
struct perf_event_attr attr = {
.type = PERF_TYPE_RAW,
.size = sizeof(attr),
.config = INTEL_FIXED_VLBR_EVENT,
.sample_type = PERF_SAMPLE_BRANCH_STACK,
.pinned = true,
.exclude_host = true,
.branch_sample_type = PERF_SAMPLE_BRANCH_CALL_STACK |
PERF_SAMPLE_BRANCH_USER,
};
if (WARN_ON_ONCE(!lbr_desc))
return 0;
if (unlikely(lbr_desc->event)) {
__set_bit(INTEL_PMC_IDX_FIXED_VLBR, pmu->pmc_in_use);
return 0;
}
event = perf_event_create_kernel_counter(&attr, -1,
current, NULL, NULL);
if (IS_ERR(event)) {
pr_debug_ratelimited("%s: failed %ld\n",
__func__, PTR_ERR(event));
return PTR_ERR(event);
}
lbr_desc->event = event;
pmu->event_count++;
__set_bit(INTEL_PMC_IDX_FIXED_VLBR, pmu->pmc_in_use);
return 0;
}
/*
* It's safe to access LBR msrs from guest when they have not
* been passthrough since the host would help restore or reset
* the LBR msrs records when the guest LBR event is scheduled in.
*/
static bool intel_pmu_handle_lbr_msrs_access(struct kvm_vcpu *vcpu,
struct msr_data *msr_info, bool read)
{
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
u32 index = msr_info->index;
if (!intel_pmu_is_valid_lbr_msr(vcpu, index))
return false;
if (!lbr_desc->event && intel_pmu_create_guest_lbr_event(vcpu) < 0)
goto dummy;
/*
* Disable irq to ensure the LBR feature doesn't get reclaimed by the
* host at the time the value is read from the msr, and this avoids the
* host LBR value to be leaked to the guest. If LBR has been reclaimed,
* return 0 on guest reads.
*/
local_irq_disable();
if (lbr_desc->event->state == PERF_EVENT_STATE_ACTIVE) {
int err = 0;
if (read)
rdmsrq(index, msr_info->data);
else
err = wrmsrq_safe(index, msr_info->data);
__set_bit(INTEL_PMC_IDX_FIXED_VLBR, vcpu_to_pmu(vcpu)->pmc_in_use);
local_irq_enable();
return !err;
}
clear_bit(INTEL_PMC_IDX_FIXED_VLBR, vcpu_to_pmu(vcpu)->pmc_in_use);
local_irq_enable();
dummy:
if (read)
msr_info->data = 0;
return true;
}
static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct kvm_pmc *pmc;
u32 msr = msr_info->index;
switch (msr) {
case MSR_CORE_PERF_FIXED_CTR_CTRL:
msr_info->data = pmu->fixed_ctr_ctrl;
break;
case MSR_IA32_PEBS_ENABLE:
msr_info->data = pmu->pebs_enable;
break;
case MSR_IA32_DS_AREA:
msr_info->data = pmu->ds_area;
break;
case MSR_PEBS_DATA_CFG:
msr_info->data = pmu->pebs_data_cfg;
break;
default:
if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
(pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) {
u64 val = pmc_read_counter(pmc);
msr_info->data =
val & pmu->counter_bitmask[KVM_PMC_GP];
break;
} else if ((pmc = get_fixed_pmc(pmu, msr))) {
u64 val = pmc_read_counter(pmc);
msr_info->data =
val & pmu->counter_bitmask[KVM_PMC_FIXED];
break;
} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
msr_info->data = pmc->eventsel;
break;
} else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, true)) {
break;
}
return 1;
}
return 0;
}
static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct kvm_pmc *pmc;
u32 msr = msr_info->index;
u64 data = msr_info->data;
u64 reserved_bits, diff;
switch (msr) {
case MSR_CORE_PERF_FIXED_CTR_CTRL:
if (data & pmu->fixed_ctr_ctrl_rsvd)
return 1;
if (pmu->fixed_ctr_ctrl != data)
reprogram_fixed_counters(pmu, data);
break;
case MSR_IA32_PEBS_ENABLE:
if (data & pmu->pebs_enable_rsvd)
return 1;
if (pmu->pebs_enable != data) {
diff = pmu->pebs_enable ^ data;
pmu->pebs_enable = data;
kvm_pmu_request_counters_reprogram(pmu, diff);
}
break;
case MSR_IA32_DS_AREA:
if (is_noncanonical_msr_address(data, vcpu))
return 1;
pmu->ds_area = data;
break;
case MSR_PEBS_DATA_CFG:
if (data & pmu->pebs_data_cfg_rsvd)
return 1;
pmu->pebs_data_cfg = data;
break;
default:
if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
(pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) {
if ((msr & MSR_PMC_FULL_WIDTH_BIT) &&
(data & ~pmu->counter_bitmask[KVM_PMC_GP]))
return 1;
if (!msr_info->host_initiated &&
!(msr & MSR_PMC_FULL_WIDTH_BIT))
data = (s64)(s32)data;
pmc_write_counter(pmc, data);
break;
} else if ((pmc = get_fixed_pmc(pmu, msr))) {
pmc_write_counter(pmc, data);
break;
} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
reserved_bits = pmu->reserved_bits;
if ((pmc->idx == 2) &&
(pmu->raw_event_mask & HSW_IN_TX_CHECKPOINTED))
reserved_bits ^= HSW_IN_TX_CHECKPOINTED;
if (data & reserved_bits)
return 1;
if (data != pmc->eventsel) {
pmc->eventsel = data;
pmc->eventsel_hw = data;
kvm_pmu_request_counter_reprogram(pmc);
}
break;
} else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, false)) {
break;
}
/* Not a known PMU MSR. */
return 1;
}
return 0;
}
/*
* Map fixed counter events to architectural general purpose event encodings.
* Perf doesn't provide APIs to allow KVM to directly program a fixed counter,
* and so KVM instead programs the architectural event to effectively request
* the fixed counter. Perf isn't guaranteed to use a fixed counter and may
* instead program the encoding into a general purpose counter, e.g. if a
* different perf_event is already utilizing the requested counter, but the end
* result is the same (ignoring the fact that using a general purpose counter
* will likely exacerbate counter contention).
*
* Forcibly inlined to allow asserting on @index at build time, and there should
* never be more than one user.
*/
static __always_inline u64 intel_get_fixed_pmc_eventsel(unsigned int index)
{
const enum perf_hw_id fixed_pmc_perf_ids[] = {
[0] = PERF_COUNT_HW_INSTRUCTIONS,
[1] = PERF_COUNT_HW_CPU_CYCLES,
[2] = PERF_COUNT_HW_REF_CPU_CYCLES,
};
u64 eventsel;
BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_perf_ids) != KVM_MAX_NR_INTEL_FIXED_COUNTERS);
BUILD_BUG_ON(index >= KVM_MAX_NR_INTEL_FIXED_COUNTERS);
/*
* Yell if perf reports support for a fixed counter but perf doesn't
* have a known encoding for the associated general purpose event.
*/
eventsel = perf_get_hw_event_config(fixed_pmc_perf_ids[index]);
WARN_ON_ONCE(!eventsel && index < kvm_pmu_cap.num_counters_fixed);
return eventsel;
}
static void intel_pmu_enable_fixed_counter_bits(struct kvm_pmu *pmu, u64 bits)
{
int i;
for (i = 0; i < pmu->nr_arch_fixed_counters; i++)
pmu->fixed_ctr_ctrl_rsvd &= ~intel_fixed_bits_by_idx(i, bits);
}
static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
struct kvm_cpuid_entry2 *entry;
union cpuid10_eax eax;
union cpuid10_edx edx;
u64 perf_capabilities;
u64 counter_rsvd;
if (!lbr_desc)
return;
memset(&lbr_desc->records, 0, sizeof(lbr_desc->records));
/*
* Setting passthrough of LBR MSRs is done only in the VM-Entry loop,
* and PMU refresh is disallowed after the vCPU has run, i.e. this code
* should never be reached while KVM is passing through MSRs.
*/
if (KVM_BUG_ON(lbr_desc->msr_passthrough, vcpu->kvm))
return;
entry = kvm_find_cpuid_entry(vcpu, 0xa);
if (!entry)
return;
eax.full = entry->eax;
edx.full = entry->edx;
pmu->version = eax.split.version_id;
if (!pmu->version)
return;
pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters,
kvm_pmu_cap.num_counters_gp);
eax.split.bit_width = min_t(int, eax.split.bit_width,
kvm_pmu_cap.bit_width_gp);
pmu->counter_bitmask[KVM_PMC_GP] = BIT_ULL(eax.split.bit_width) - 1;
eax.split.mask_length = min_t(int, eax.split.mask_length,
kvm_pmu_cap.events_mask_len);
pmu->available_event_types = ~entry->ebx & (BIT_ULL(eax.split.mask_length) - 1);
entry = kvm_find_cpuid_entry_index(vcpu, 7, 0);
if (entry &&
(boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) &&
(entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM))) {
pmu->reserved_bits ^= HSW_IN_TX;
pmu->raw_event_mask |= (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED);
}
perf_capabilities = vcpu_get_perf_capabilities(vcpu);
if (intel_pmu_lbr_is_compatible(vcpu) &&
(perf_capabilities & PERF_CAP_LBR_FMT))
memcpy(&lbr_desc->records, &vmx_lbr_caps, sizeof(vmx_lbr_caps));
else
lbr_desc->records.nr = 0;
if (lbr_desc->records.nr)
bitmap_set(pmu->all_valid_pmc_idx, INTEL_PMC_IDX_FIXED_VLBR, 1);
if (pmu->version == 1)
return;
pmu->nr_arch_fixed_counters = min_t(int, edx.split.num_counters_fixed,
kvm_pmu_cap.num_counters_fixed);
edx.split.bit_width_fixed = min_t(int, edx.split.bit_width_fixed,
kvm_pmu_cap.bit_width_fixed);
pmu->counter_bitmask[KVM_PMC_FIXED] = BIT_ULL(edx.split.bit_width_fixed) - 1;
intel_pmu_enable_fixed_counter_bits(pmu, INTEL_FIXED_0_KERNEL |
INTEL_FIXED_0_USER |
INTEL_FIXED_0_ENABLE_PMI);
counter_rsvd = ~((BIT_ULL(pmu->nr_arch_gp_counters) - 1) |
((BIT_ULL(pmu->nr_arch_fixed_counters) - 1) << KVM_FIXED_PMC_BASE_IDX));
pmu->global_ctrl_rsvd = counter_rsvd;
/*
* GLOBAL_STATUS and GLOBAL_OVF_CONTROL (a.k.a. GLOBAL_STATUS_RESET)
* share reserved bit definitions. The kernel just happens to use
* OVF_CTRL for the names.
*/
pmu->global_status_rsvd = pmu->global_ctrl_rsvd
& ~(MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF |
MSR_CORE_PERF_GLOBAL_OVF_CTRL_COND_CHGD);
if (vmx_pt_mode_is_host_guest())
pmu->global_status_rsvd &=
~MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI;
if (perf_capabilities & PERF_CAP_PEBS_FORMAT) {
if (perf_capabilities & PERF_CAP_PEBS_BASELINE) {
pmu->pebs_enable_rsvd = counter_rsvd;
pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE;
pmu->pebs_data_cfg_rsvd = ~0xff00000full;
intel_pmu_enable_fixed_counter_bits(pmu, ICL_FIXED_0_ADAPTIVE);
} else {
pmu->pebs_enable_rsvd = ~(BIT_ULL(pmu->nr_arch_gp_counters) - 1);
}
}
}
static void intel_pmu_init(struct kvm_vcpu *vcpu)
{
int i;
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
if (!lbr_desc)
return;
for (i = 0; i < KVM_MAX_NR_INTEL_GP_COUNTERS; i++) {
pmu->gp_counters[i].type = KVM_PMC_GP;
pmu->gp_counters[i].vcpu = vcpu;
pmu->gp_counters[i].idx = i;
pmu->gp_counters[i].current_config = 0;
}
for (i = 0; i < KVM_MAX_NR_INTEL_FIXED_COUNTERS; i++) {
pmu->fixed_counters[i].type = KVM_PMC_FIXED;
pmu->fixed_counters[i].vcpu = vcpu;
pmu->fixed_counters[i].idx = i + KVM_FIXED_PMC_BASE_IDX;
pmu->fixed_counters[i].current_config = 0;
pmu->fixed_counters[i].eventsel = intel_get_fixed_pmc_eventsel(i);
}
lbr_desc->records.nr = 0;
lbr_desc->event = NULL;
lbr_desc->msr_passthrough = false;
}
static void intel_pmu_reset(struct kvm_vcpu *vcpu)
{
intel_pmu_release_guest_lbr_event(vcpu);
}
/*
* Emulate LBR_On_PMI behavior for 1 < pmu.version < 4.
*
* If Freeze_LBR_On_PMI = 1, the LBR is frozen on PMI and
* the KVM emulates to clear the LBR bit (bit 0) in IA32_DEBUGCTL.
*
* Guest needs to re-enable LBR to resume branches recording.
*/
static void intel_pmu_legacy_freezing_lbrs_on_pmi(struct kvm_vcpu *vcpu)
{
u64 data = vmx_guest_debugctl_read();
if (data & DEBUGCTLMSR_FREEZE_LBRS_ON_PMI) {
data &= ~DEBUGCTLMSR_LBR;
vmx_guest_debugctl_write(vcpu, data);
}
}
static void intel_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
{
u8 version = vcpu_to_pmu(vcpu)->version;
if (!intel_pmu_lbr_is_enabled(vcpu))
return;
if (version > 1 && version < 4)
intel_pmu_legacy_freezing_lbrs_on_pmi(vcpu);
}
static void vmx_update_intercept_for_lbr_msrs(struct kvm_vcpu *vcpu, bool set)
{
struct x86_pmu_lbr *lbr = vcpu_to_lbr_records(vcpu);
int i;
for (i = 0; i < lbr->nr; i++) {
vmx_set_intercept_for_msr(vcpu, lbr->from + i, MSR_TYPE_RW, set);
vmx_set_intercept_for_msr(vcpu, lbr->to + i, MSR_TYPE_RW, set);
if (lbr->info)
vmx_set_intercept_for_msr(vcpu, lbr->info + i, MSR_TYPE_RW, set);
}
vmx_set_intercept_for_msr(vcpu, MSR_LBR_SELECT, MSR_TYPE_RW, set);
vmx_set_intercept_for_msr(vcpu, MSR_LBR_TOS, MSR_TYPE_RW, set);
}
static inline void vmx_disable_lbr_msrs_passthrough(struct kvm_vcpu *vcpu)
{
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
if (!lbr_desc->msr_passthrough)
return;
vmx_update_intercept_for_lbr_msrs(vcpu, true);
lbr_desc->msr_passthrough = false;
}
static inline void vmx_enable_lbr_msrs_passthrough(struct kvm_vcpu *vcpu)
{
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
if (lbr_desc->msr_passthrough)
return;
vmx_update_intercept_for_lbr_msrs(vcpu, false);
lbr_desc->msr_passthrough = true;
}
/*
* Higher priority host perf events (e.g. cpu pinned) could reclaim the
* pmu resources (e.g. LBR) that were assigned to the guest. This is
* usually done via ipi calls (more details in perf_install_in_context).
*
* Before entering the non-root mode (with irq disabled here), double
* confirm that the pmu features enabled to the guest are not reclaimed
* by higher priority host events. Otherwise, disallow vcpu's access to
* the reclaimed features.
*/
void vmx_passthrough_lbr_msrs(struct kvm_vcpu *vcpu)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
if (WARN_ON_ONCE(!lbr_desc))
return;
if (!lbr_desc->event) {
vmx_disable_lbr_msrs_passthrough(vcpu);
if (vmx_guest_debugctl_read() & DEBUGCTLMSR_LBR)
goto warn;
if (test_bit(INTEL_PMC_IDX_FIXED_VLBR, pmu->pmc_in_use))
goto warn;
return;
}
if (lbr_desc->event->state < PERF_EVENT_STATE_ACTIVE) {
vmx_disable_lbr_msrs_passthrough(vcpu);
__clear_bit(INTEL_PMC_IDX_FIXED_VLBR, pmu->pmc_in_use);
goto warn;
} else
vmx_enable_lbr_msrs_passthrough(vcpu);
return;
warn:
pr_warn_ratelimited("vcpu-%d: fail to passthrough LBR.\n", vcpu->vcpu_id);
}
static void intel_pmu_cleanup(struct kvm_vcpu *vcpu)
{
if (!(vmx_guest_debugctl_read() & DEBUGCTLMSR_LBR))
intel_pmu_release_guest_lbr_event(vcpu);
}
void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
{
struct kvm_pmc *pmc = NULL;
int bit, hw_idx;
kvm_for_each_pmc(pmu, pmc, bit, (unsigned long *)&pmu->global_ctrl) {
if (!pmc_is_locally_enabled(pmc) ||
!pmc_is_globally_enabled(pmc) || !pmc->perf_event)
continue;
/*
* A negative index indicates the event isn't mapped to a
* physical counter in the host, e.g. due to contention.
*/
hw_idx = pmc->perf_event->hw.idx;
if (hw_idx != pmc->idx && hw_idx > -1)
pmu->host_cross_mapped_mask |= BIT_ULL(hw_idx);
}
}
static bool intel_pmu_is_mediated_pmu_supported(struct x86_pmu_capability *host_pmu)
{
u64 host_perf_cap = 0;
if (boot_cpu_has(X86_FEATURE_PDCM))
rdmsrq(MSR_IA32_PERF_CAPABILITIES, host_perf_cap);
/*
* Require v4+ for MSR_CORE_PERF_GLOBAL_STATUS_SET, and full-width
* writes so that KVM can precisely load guest counter values.
*/
if (host_pmu->version < 4 || !(host_perf_cap & PERF_CAP_FW_WRITES))
return false;
/*
* All CPUs that support a mediated PMU are expected to support loading
* PERF_GLOBAL_CTRL via dedicated VMCS fields.
*/
if (WARN_ON_ONCE(!cpu_has_load_perf_global_ctrl()))
return false;
return true;
}
static void intel_pmu_write_global_ctrl(u64 global_ctrl)
{
vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, global_ctrl);
}
static void intel_mediated_pmu_load(struct kvm_vcpu *vcpu)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
u64 global_status, toggle;
rdmsrq(MSR_CORE_PERF_GLOBAL_STATUS, global_status);
toggle = pmu->global_status ^ global_status;
if (global_status & toggle)
wrmsrq(MSR_CORE_PERF_GLOBAL_OVF_CTRL, global_status & toggle);
if (pmu->global_status & toggle)
wrmsrq(MSR_CORE_PERF_GLOBAL_STATUS_SET, pmu->global_status & toggle);
wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, pmu->fixed_ctr_ctrl_hw);
}
static void intel_mediated_pmu_put(struct kvm_vcpu *vcpu)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
/* MSR_CORE_PERF_GLOBAL_CTRL is already saved at VM-exit. */
rdmsrq(MSR_CORE_PERF_GLOBAL_STATUS, pmu->global_status);
/* Clear hardware MSR_CORE_PERF_GLOBAL_STATUS MSR, if non-zero. */
if (pmu->global_status)
wrmsrq(MSR_CORE_PERF_GLOBAL_OVF_CTRL, pmu->global_status);
/*
* Clear hardware FIXED_CTR_CTRL MSR to avoid information leakage and
* also to avoid accidentally enabling fixed counters (based on guest
* state) while running in the host, e.g. when setting global ctrl.
*/
if (pmu->fixed_ctr_ctrl_hw)
wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
}
struct kvm_pmu_ops intel_pmu_ops __initdata = {
.rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc,
.msr_idx_to_pmc = intel_msr_idx_to_pmc,
.is_valid_msr = intel_is_valid_msr,
.get_msr = intel_pmu_get_msr,
.set_msr = intel_pmu_set_msr,
.refresh = intel_pmu_refresh,
.init = intel_pmu_init,
.reset = intel_pmu_reset,
.deliver_pmi = intel_pmu_deliver_pmi,
.cleanup = intel_pmu_cleanup,
.is_mediated_pmu_supported = intel_pmu_is_mediated_pmu_supported,
.mediated_load = intel_mediated_pmu_load,
.mediated_put = intel_mediated_pmu_put,
.write_global_ctrl = intel_pmu_write_global_ctrl,
.EVENTSEL_EVENT = ARCH_PERFMON_EVENTSEL_EVENT,
.MAX_NR_GP_COUNTERS = KVM_MAX_NR_INTEL_GP_COUNTERS,
.MIN_NR_GP_COUNTERS = 1,
.PERF_GLOBAL_CTRL = MSR_CORE_PERF_GLOBAL_CTRL,
.GP_EVENTSEL_BASE = MSR_P6_EVNTSEL0,
.GP_COUNTER_BASE = MSR_IA32_PMC0,
.FIXED_COUNTER_BASE = MSR_CORE_PERF_FIXED_CTR0,
.MSR_STRIDE = 1,
};
+43
View File
@@ -0,0 +1,43 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_PMU_INTEL_H
#define __KVM_X86_VMX_PMU_INTEL_H
#include <linux/kvm_host.h>
#include "cpuid.h"
static inline u64 vcpu_get_perf_capabilities(struct kvm_vcpu *vcpu)
{
if (!guest_cpu_cap_has(vcpu, X86_FEATURE_PDCM))
return 0;
return vcpu->arch.perf_capabilities;
}
static inline bool fw_writes_is_enabled(struct kvm_vcpu *vcpu)
{
return (vcpu_get_perf_capabilities(vcpu) & PERF_CAP_FW_WRITES) != 0;
}
bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu);
int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu);
struct lbr_desc {
/* Basic info about guest LBR records. */
struct x86_pmu_lbr records;
/*
* Emulate LBR feature via passthrough LBR registers when the
* per-vcpu guest LBR event is scheduled on the current pcpu.
*
* The records may be inaccurate if the host reclaims the LBR.
*/
struct perf_event *event;
/* True if LBRs are marked as not intercepted in the MSR bitmap */
bool msr_passthrough;
};
extern struct x86_pmu_lbr vmx_lbr_caps;
#endif /* __KVM_X86_VMX_PMU_INTEL_H */
+319
View File
@@ -0,0 +1,319 @@
// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kvm_host.h>
#include <linux/kvm_irqfd.h>
#include <asm/irq_remapping.h>
#include <asm/cpu.h>
#include "lapic.h"
#include "irq.h"
#include "posted_intr.h"
#include "trace.h"
#include "vmx.h"
#include "tdx.h"
/*
* Maintain a per-CPU list of vCPUs that need to be awakened by wakeup_handler()
* when a WAKEUP_VECTOR interrupted is posted. vCPUs are added to the list when
* the vCPU is scheduled out and is blocking (e.g. in HLT) with IRQs enabled.
* The vCPUs posted interrupt descriptor is updated at the same time to set its
* notification vector to WAKEUP_VECTOR, so that posted interrupt from devices
* wake the target vCPUs. vCPUs are removed from the list and the notification
* vector is reset when the vCPU is scheduled in.
*/
static DEFINE_PER_CPU(struct list_head, wakeup_vcpus_on_cpu);
/*
* Protect the per-CPU list with a per-CPU spinlock to handle task migration.
* When a blocking vCPU is awakened _and_ migrated to a different pCPU, the
* ->sched_in() path will need to take the vCPU off the list of the _previous_
* CPU. IRQs must be disabled when taking this lock, otherwise deadlock will
* occur if a wakeup IRQ arrives and attempts to acquire the lock.
*/
static DEFINE_PER_CPU(raw_spinlock_t, wakeup_vcpus_on_cpu_lock);
#define PI_LOCK_SCHED_OUT SINGLE_DEPTH_NESTING
static struct pi_desc *vcpu_to_pi_desc(struct kvm_vcpu *vcpu)
{
return &(to_vt(vcpu)->pi_desc);
}
static int pi_try_set_control(struct pi_desc *pi_desc, u64 *pold, u64 new)
{
/*
* PID.ON can be set at any time by a different vCPU or by hardware,
* e.g. a device. PID.control must be written atomically, and the
* update must be retried with a fresh snapshot an ON change causes
* the cmpxchg to fail.
*/
if (!try_cmpxchg64(&pi_desc->control, pold, new))
return -EBUSY;
return 0;
}
void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu)
{
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
struct vcpu_vt *vt = to_vt(vcpu);
struct pi_desc old, new;
unsigned long flags;
unsigned int dest;
/*
* To simplify hot-plug and dynamic toggling of APICv, keep PI.NDST and
* PI.SN up-to-date even if there is no assigned device or if APICv is
* deactivated due to a dynamic inhibit bit, e.g. for Hyper-V's SyncIC.
*/
if (!enable_apicv || !lapic_in_kernel(vcpu))
return;
/*
* If the vCPU wasn't on the wakeup list and wasn't migrated, then the
* full update can be skipped as neither the vector nor the destination
* needs to be changed. Clear SN even if there is no assigned device,
* again for simplicity.
*/
if (pi_desc->nv != POSTED_INTR_WAKEUP_VECTOR && vcpu->cpu == cpu) {
if (pi_test_and_clear_sn(pi_desc))
goto after_clear_sn;
return;
}
local_irq_save(flags);
/*
* If the vCPU was waiting for wakeup, remove the vCPU from the wakeup
* list of the _previous_ pCPU, which will not be the same as the
* current pCPU if the task was migrated.
*/
if (pi_desc->nv == POSTED_INTR_WAKEUP_VECTOR) {
raw_spinlock_t *spinlock = &per_cpu(wakeup_vcpus_on_cpu_lock, vcpu->cpu);
/*
* In addition to taking the wakeup lock for the regular/IRQ
* context, tell lockdep it is being taken for the "sched out"
* context as well. vCPU loads happens in task context, and
* this is taking the lock of the *previous* CPU, i.e. can race
* with both the scheduler and the wakeup handler.
*/
raw_spin_lock(spinlock);
spin_acquire(&spinlock->dep_map, PI_LOCK_SCHED_OUT, 0, _RET_IP_);
list_del(&vt->pi_wakeup_list);
spin_release(&spinlock->dep_map, _RET_IP_);
raw_spin_unlock(spinlock);
}
dest = cpu_physical_id(cpu);
if (!x2apic_mode)
dest = (dest << 8) & 0xFF00;
old.control = READ_ONCE(pi_desc->control);
do {
new.control = old.control;
/*
* Clear SN (as above) and refresh the destination APIC ID to
* handle task migration (@cpu != vcpu->cpu).
*/
new.ndst = dest;
__pi_clear_sn(&new);
/*
* Restore the notification vector; in the blocking case, the
* descriptor was modified on "put" to use the wakeup vector.
*/
new.nv = POSTED_INTR_VECTOR;
} while (pi_try_set_control(pi_desc, &old.control, new.control));
local_irq_restore(flags);
after_clear_sn:
/*
* Clear SN before reading the bitmap. The VT-d firmware
* writes the bitmap and reads SN atomically (5.2.3 in the
* spec), so it doesn't really have a memory barrier that
* pairs with this, but we cannot do that and we need one.
*/
smp_mb__after_atomic();
if (!pi_is_pir_empty(pi_desc))
pi_set_on(pi_desc);
}
static bool vmx_can_use_vtd_pi(struct kvm *kvm)
{
/*
* Note, reading the number of possible bypass IRQs can race with a
* bypass IRQ being attached to the VM. vmx_pi_start_bypass() ensures
* blockng vCPUs will see an elevated count or get KVM_REQ_UNBLOCK.
*/
return irqchip_in_kernel(kvm) && kvm_arch_has_irq_bypass() &&
READ_ONCE(kvm->arch.nr_possible_bypass_irqs);
}
/*
* Put the vCPU on this pCPU's list of vCPUs that needs to be awakened and set
* WAKEUP as the notification vector in the PI descriptor.
*/
static void pi_enable_wakeup_handler(struct kvm_vcpu *vcpu)
{
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
struct vcpu_vt *vt = to_vt(vcpu);
struct pi_desc old, new;
lockdep_assert_irqs_disabled();
/*
* Acquire the wakeup lock using the "sched out" context to workaround
* a lockdep false positive. When this is called, schedule() holds
* various per-CPU scheduler locks. When the wakeup handler runs, it
* holds this CPU's wakeup lock while calling try_to_wake_up(), which
* can eventually take the aforementioned scheduler locks, which causes
* lockdep to assume there is deadlock.
*
* Deadlock can't actually occur because IRQs are disabled for the
* entirety of the sched_out critical section, i.e. the wakeup handler
* can't run while the scheduler locks are held.
*/
raw_spin_lock_nested(&per_cpu(wakeup_vcpus_on_cpu_lock, vcpu->cpu),
PI_LOCK_SCHED_OUT);
list_add_tail(&vt->pi_wakeup_list,
&per_cpu(wakeup_vcpus_on_cpu, vcpu->cpu));
raw_spin_unlock(&per_cpu(wakeup_vcpus_on_cpu_lock, vcpu->cpu));
WARN(pi_test_sn(pi_desc), "PI descriptor SN field set before blocking");
old.control = READ_ONCE(pi_desc->control);
do {
/* set 'NV' to 'wakeup vector' */
new.control = old.control;
new.nv = POSTED_INTR_WAKEUP_VECTOR;
} while (pi_try_set_control(pi_desc, &old.control, new.control));
/*
* Send a wakeup IPI to this CPU if an interrupt may have been posted
* before the notification vector was updated, in which case the IRQ
* will arrive on the non-wakeup vector. An IPI is needed as calling
* try_to_wake_up() from ->sched_out() isn't allowed (IRQs are not
* enabled until it is safe to call try_to_wake_up() on the task being
* scheduled out).
*/
if (pi_test_on(&new))
__apic_send_IPI_self(POSTED_INTR_WAKEUP_VECTOR);
}
static bool vmx_needs_pi_wakeup(struct kvm_vcpu *vcpu)
{
/*
* The default posted interrupt vector does nothing when
* invoked outside guest mode. Return whether a blocked vCPU
* can be the target of posted interrupts, as is the case when
* using either IPI virtualization or VT-d PI, so that the
* notification vector is switched to the one that calls
* back to the pi_wakeup_handler() function.
*/
return (vmx_can_use_ipiv(vcpu) && !is_td_vcpu(vcpu)) ||
vmx_can_use_vtd_pi(vcpu->kvm);
}
void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu)
{
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
if (!vmx_needs_pi_wakeup(vcpu))
return;
/*
* If the vCPU is blocking with IRQs enabled and ISN'T being preempted,
* enable the wakeup handler so that notification IRQ wakes the vCPU as
* expected. There is no need to enable the wakeup handler if the vCPU
* is preempted between setting its wait state and manually scheduling
* out, as the task is still runnable, i.e. doesn't need a wake event
* from KVM to be scheduled in.
*
* If the wakeup handler isn't being enabled, Suppress Notifications as
* the cost of propagating PIR.IRR to PID.ON is negligible compared to
* the cost of a spurious IRQ, and vCPU put/load is a slow path.
*/
if (!vcpu->preempted && kvm_vcpu_is_blocking(vcpu) &&
((is_td_vcpu(vcpu) && tdx_interrupt_allowed(vcpu)) ||
(!is_td_vcpu(vcpu) && !vmx_interrupt_blocked(vcpu))))
pi_enable_wakeup_handler(vcpu);
else
pi_set_sn(pi_desc);
}
/*
* Handler for POSTED_INTERRUPT_WAKEUP_VECTOR.
*/
void pi_wakeup_handler(void)
{
int cpu = smp_processor_id();
struct list_head *wakeup_list = &per_cpu(wakeup_vcpus_on_cpu, cpu);
raw_spinlock_t *spinlock = &per_cpu(wakeup_vcpus_on_cpu_lock, cpu);
struct vcpu_vt *vt;
raw_spin_lock(spinlock);
list_for_each_entry(vt, wakeup_list, pi_wakeup_list) {
if (pi_test_on(&vt->pi_desc))
kvm_vcpu_wake_up(vt_to_vcpu(vt));
}
raw_spin_unlock(spinlock);
}
void __init pi_init_cpu(int cpu)
{
INIT_LIST_HEAD(&per_cpu(wakeup_vcpus_on_cpu, cpu));
raw_spin_lock_init(&per_cpu(wakeup_vcpus_on_cpu_lock, cpu));
}
void pi_apicv_pre_state_restore(struct kvm_vcpu *vcpu)
{
struct pi_desc *pi = vcpu_to_pi_desc(vcpu);
pi_clear_on(pi);
memset(pi->pir, 0, sizeof(pi->pir));
}
bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu)
{
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
return pi_test_on(pi_desc) ||
(pi_test_sn(pi_desc) && !pi_is_pir_empty(pi_desc));
}
/*
* Kick all vCPUs when the first possible bypass IRQ is attached to a VM, as
* blocking vCPUs may scheduled out without reconfiguring PID.NV to the wakeup
* vector, i.e. if the bypass IRQ came along after vmx_vcpu_pi_put().
*/
void vmx_pi_start_bypass(struct kvm *kvm)
{
if (WARN_ON_ONCE(!vmx_can_use_vtd_pi(kvm)))
return;
kvm_make_all_cpus_request(kvm, KVM_REQ_UNBLOCK);
}
int vmx_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
unsigned int host_irq, uint32_t guest_irq,
struct kvm_vcpu *vcpu, u32 vector)
{
if (vcpu) {
struct intel_iommu_pi_data pi_data = {
.pi_desc_addr = __pa(vcpu_to_pi_desc(vcpu)),
.vector = vector,
};
return irq_set_vcpu_affinity(host_irq, &pi_data);
} else {
return irq_set_vcpu_affinity(host_irq, NULL);
}
}
@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_POSTED_INTR_H
#define __KVM_X86_VMX_POSTED_INTR_H
#include <linux/bitmap.h>
#include <linux/find.h>
#include <linux/kvm_host.h>
#include <asm/posted_intr.h>
void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu);
void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu);
void pi_wakeup_handler(void);
void __init pi_init_cpu(int cpu);
void pi_apicv_pre_state_restore(struct kvm_vcpu *vcpu);
bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu);
int vmx_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
unsigned int host_irq, uint32_t guest_irq,
struct kvm_vcpu *vcpu, u32 vector);
void vmx_pi_start_bypass(struct kvm *kvm);
static inline int pi_find_highest_vector(struct pi_desc *pi_desc)
{
int vec;
vec = find_last_bit(pi_desc->pir, 256);
return vec < 256 ? vec : -1;
}
#endif /* __KVM_X86_VMX_POSTED_INTR_H */
+511
View File
@@ -0,0 +1,511 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2021 Intel Corporation. */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/cpuid/api.h>
#include <asm/msr.h>
#include <asm/sgx.h>
#include "x86.h"
#include "regs.h"
#include "nested.h"
#include "sgx.h"
#include "vmx.h"
bool __read_mostly enable_sgx = 1;
module_param_named(sgx, enable_sgx, bool, 0444);
/* Initial value of guest's virtual SGX_LEPUBKEYHASHn MSRs */
static u64 sgx_pubkey_hash[4] __ro_after_init;
/*
* ENCLS's memory operands use a fixed segment (DS) and a fixed
* address size based on the mode. Related prefixes are ignored.
*/
static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset,
int size, int alignment, gva_t *gva)
{
struct kvm_segment s;
bool fault;
/* Skip vmcs.GUEST_DS retrieval for 64-bit mode to avoid VMREADs. */
*gva = offset;
if (!is_64_bit_mode(vcpu)) {
vmx_get_segment(vcpu, &s, VCPU_SREG_DS);
*gva += s.base;
}
if (!IS_ALIGNED(*gva, alignment)) {
fault = true;
} else if (likely(is_64_bit_mode(vcpu))) {
*gva = vmx_get_untagged_addr(vcpu, *gva, 0);
fault = is_noncanonical_address(*gva, vcpu, 0);
} else {
*gva &= 0xffffffff;
fault = (s.unusable) ||
(s.type != 2 && s.type != 3) ||
(*gva > s.limit) ||
((s.base != 0 || s.limit != 0xffffffff) &&
(((u64)*gva + size - 1) > s.limit + 1));
}
if (fault)
kvm_inject_gp(vcpu, 0);
return fault ? -EINVAL : 0;
}
static void sgx_handle_emulation_failure(struct kvm_vcpu *vcpu, u64 addr,
unsigned int size)
{
uint64_t data[2] = { addr, size };
__kvm_prepare_emulation_failure_exit(vcpu, data, ARRAY_SIZE(data));
}
static int sgx_read_hva(struct kvm_vcpu *vcpu, unsigned long hva, void *data,
unsigned int size)
{
if (__copy_from_user(data, (void __user *)hva, size)) {
sgx_handle_emulation_failure(vcpu, hva, size);
return -EFAULT;
}
return 0;
}
static int sgx_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t gva, bool write,
gpa_t *gpa)
{
struct x86_exception ex;
if (write)
*gpa = kvm_mmu_gva_to_gpa_write(vcpu, gva, &ex);
else
*gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, &ex);
if (*gpa == INVALID_GPA) {
kvm_inject_emulated_page_fault(vcpu, &ex);
return -EFAULT;
}
return 0;
}
static int sgx_gpa_to_hva(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned long *hva)
{
*hva = kvm_vcpu_gfn_to_hva(vcpu, PFN_DOWN(gpa));
if (kvm_is_error_hva(*hva)) {
sgx_handle_emulation_failure(vcpu, gpa, 1);
return -EFAULT;
}
*hva |= gpa & ~PAGE_MASK;
return 0;
}
static int sgx_inject_fault(struct kvm_vcpu *vcpu, gva_t gva, int trapnr)
{
struct x86_exception ex;
/*
* A non-EPCM #PF indicates a bad userspace HVA. This *should* check
* for PFEC.SGX and not assume any #PF on SGX2 originated in the EPC,
* but the error code isn't (yet) plumbed through the ENCLS helpers.
*/
if (trapnr == PF_VECTOR && !boot_cpu_has(X86_FEATURE_SGX2)) {
kvm_prepare_emulation_failure_exit(vcpu);
return 0;
}
/*
* If the guest thinks it's running on SGX2 hardware, inject an SGX
* #PF if the fault matches an EPCM fault signature (#GP on SGX1,
* #PF on SGX2). The assumption is that EPCM faults are much more
* likely than a bad userspace address.
*/
if ((trapnr == PF_VECTOR || !boot_cpu_has(X86_FEATURE_SGX2)) &&
guest_cpu_cap_has(vcpu, X86_FEATURE_SGX2)) {
memset(&ex, 0, sizeof(ex));
ex.vector = PF_VECTOR;
ex.error_code = PFERR_PRESENT_MASK | PFERR_WRITE_MASK |
PFERR_SGX_MASK;
ex.address = gva;
ex.error_code_valid = true;
ex.nested_page_fault = false;
kvm_inject_emulated_page_fault(vcpu, &ex);
} else {
kvm_inject_gp(vcpu, 0);
}
return 1;
}
static int __handle_encls_ecreate(struct kvm_vcpu *vcpu,
struct sgx_pageinfo *pageinfo,
unsigned long secs_hva,
gva_t secs_gva)
{
struct sgx_secs *contents = (struct sgx_secs *)pageinfo->contents;
struct kvm_cpuid_entry2 *sgx_12_0, *sgx_12_1;
u64 attributes, xfrm, size;
u32 miscselect;
u8 max_size_log2;
int trapnr, ret;
sgx_12_0 = kvm_find_cpuid_entry_index(vcpu, 0x12, 0);
sgx_12_1 = kvm_find_cpuid_entry_index(vcpu, 0x12, 1);
if (!sgx_12_0 || !sgx_12_1) {
kvm_prepare_emulation_failure_exit(vcpu);
return 0;
}
miscselect = contents->miscselect;
attributes = contents->attributes;
xfrm = contents->xfrm;
size = contents->size;
/* Enforce restriction of access to the PROVISIONKEY. */
if (!vcpu->kvm->arch.sgx_provisioning_allowed &&
(attributes & SGX_ATTR_PROVISIONKEY)) {
if (sgx_12_1->eax & SGX_ATTR_PROVISIONKEY)
pr_warn_once("SGX PROVISIONKEY advertised but not allowed\n");
kvm_inject_gp(vcpu, 0);
return 1;
}
/*
* Enforce CPUID restrictions on MISCSELECT, ATTRIBUTES and XFRM. Note
* that the allowed XFRM (XFeature Request Mask) isn't strictly bound
* by the supported XCR0. FP+SSE *must* be set in XFRM, even if XSAVE
* is unsupported, i.e. even if XCR0 itself is completely unsupported.
*/
if ((u32)miscselect & ~sgx_12_0->ebx ||
(u32)attributes & ~sgx_12_1->eax ||
(u32)(attributes >> 32) & ~sgx_12_1->ebx ||
(u32)xfrm & ~sgx_12_1->ecx ||
(u32)(xfrm >> 32) & ~sgx_12_1->edx ||
xfrm & ~(vcpu->arch.guest_supported_xcr0 | XFEATURE_MASK_FPSSE) ||
(xfrm & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) {
kvm_inject_gp(vcpu, 0);
return 1;
}
/* Enforce CPUID restriction on max enclave size. */
max_size_log2 = (attributes & SGX_ATTR_MODE64BIT) ? sgx_12_0->edx >> 8 :
sgx_12_0->edx;
if (size >= BIT_ULL(max_size_log2)) {
kvm_inject_gp(vcpu, 0);
return 1;
}
/*
* sgx_virt_ecreate() returns:
* 1) 0: ECREATE was successful
* 2) -EFAULT: ECREATE was run but faulted, and trapnr was set to the
* exception number.
* 3) -EINVAL: access_ok() on @secs_hva failed. This should never
* happen as KVM checks host addresses at memslot creation.
* sgx_virt_ecreate() has already warned in this case.
*/
ret = sgx_virt_ecreate(pageinfo, (void __user *)secs_hva, &trapnr);
if (!ret)
return kvm_skip_emulated_instruction(vcpu);
if (ret == -EFAULT)
return sgx_inject_fault(vcpu, secs_gva, trapnr);
return ret;
}
static int handle_encls_ecreate(struct kvm_vcpu *vcpu)
{
gva_t pageinfo_gva, secs_gva;
gva_t metadata_gva, contents_gva;
gpa_t metadata_gpa, contents_gpa, secs_gpa;
unsigned long metadata_hva, contents_hva, secs_hva;
struct sgx_pageinfo pageinfo;
struct sgx_secs *contents;
struct x86_exception ex;
int r;
if (sgx_get_encls_gva(vcpu, kvm_rbx_read(vcpu), 32, 32, &pageinfo_gva) ||
sgx_get_encls_gva(vcpu, kvm_rcx_read(vcpu), 4096, 4096, &secs_gva))
return 1;
/*
* Copy the PAGEINFO to local memory, its pointers need to be
* translated, i.e. we need to do a deep copy/translate.
*/
r = kvm_read_guest_virt(vcpu, pageinfo_gva, &pageinfo,
sizeof(pageinfo), &ex);
if (r == X86EMUL_PROPAGATE_FAULT) {
kvm_inject_emulated_page_fault(vcpu, &ex);
return 1;
} else if (r != X86EMUL_CONTINUE) {
sgx_handle_emulation_failure(vcpu, pageinfo_gva,
sizeof(pageinfo));
return 0;
}
if (sgx_get_encls_gva(vcpu, pageinfo.metadata, 64, 64, &metadata_gva) ||
sgx_get_encls_gva(vcpu, pageinfo.contents, 4096, 4096,
&contents_gva))
return 1;
/*
* Translate the SECINFO, SOURCE and SECS pointers from GVA to GPA.
* Resume the guest on failure to inject a #PF.
*/
if (sgx_gva_to_gpa(vcpu, metadata_gva, false, &metadata_gpa) ||
sgx_gva_to_gpa(vcpu, contents_gva, false, &contents_gpa) ||
sgx_gva_to_gpa(vcpu, secs_gva, true, &secs_gpa))
return 1;
/*
* ...and then to HVA. The order of accesses isn't architectural, i.e.
* KVM doesn't have to fully process one address at a time. Exit to
* userspace if a GPA is invalid.
*/
if (sgx_gpa_to_hva(vcpu, metadata_gpa, &metadata_hva) ||
sgx_gpa_to_hva(vcpu, contents_gpa, &contents_hva) ||
sgx_gpa_to_hva(vcpu, secs_gpa, &secs_hva))
return 0;
/*
* Copy contents into kernel memory to prevent TOCTOU attack. E.g. the
* guest could do ECREATE w/ SECS.SGX_ATTR_PROVISIONKEY=0, and
* simultaneously set SGX_ATTR_PROVISIONKEY to bypass the check to
* enforce restriction of access to the PROVISIONKEY.
*/
contents = (struct sgx_secs *)__get_free_page(GFP_KERNEL);
if (!contents)
return -ENOMEM;
/* Exit to userspace if copying from a host userspace address fails. */
if (sgx_read_hva(vcpu, contents_hva, (void *)contents, PAGE_SIZE)) {
free_page((unsigned long)contents);
return 0;
}
pageinfo.metadata = metadata_hva;
pageinfo.contents = (u64)contents;
r = __handle_encls_ecreate(vcpu, &pageinfo, secs_hva, secs_gva);
free_page((unsigned long)contents);
return r;
}
static int handle_encls_einit(struct kvm_vcpu *vcpu)
{
unsigned long sig_hva, secs_hva, token_hva, rflags;
struct vcpu_vmx *vmx = to_vmx(vcpu);
gva_t sig_gva, secs_gva, token_gva;
gpa_t sig_gpa, secs_gpa, token_gpa;
int ret, trapnr;
if (sgx_get_encls_gva(vcpu, kvm_rbx_read(vcpu), 1808, 4096, &sig_gva) ||
sgx_get_encls_gva(vcpu, kvm_rcx_read(vcpu), 4096, 4096, &secs_gva) ||
sgx_get_encls_gva(vcpu, kvm_rdx_read(vcpu), 304, 512, &token_gva))
return 1;
/*
* Translate the SIGSTRUCT, SECS and TOKEN pointers from GVA to GPA.
* Resume the guest on failure to inject a #PF.
*/
if (sgx_gva_to_gpa(vcpu, sig_gva, false, &sig_gpa) ||
sgx_gva_to_gpa(vcpu, secs_gva, true, &secs_gpa) ||
sgx_gva_to_gpa(vcpu, token_gva, false, &token_gpa))
return 1;
/*
* ...and then to HVA. The order of accesses isn't architectural, i.e.
* KVM doesn't have to fully process one address at a time. Exit to
* userspace if a GPA is invalid. Note, all structures are aligned and
* cannot split pages.
*/
if (sgx_gpa_to_hva(vcpu, sig_gpa, &sig_hva) ||
sgx_gpa_to_hva(vcpu, secs_gpa, &secs_hva) ||
sgx_gpa_to_hva(vcpu, token_gpa, &token_hva))
return 0;
ret = sgx_virt_einit((void __user *)sig_hva, (void __user *)token_hva,
(void __user *)secs_hva,
vmx->msr_ia32_sgxlepubkeyhash, &trapnr);
if (ret == -EFAULT)
return sgx_inject_fault(vcpu, secs_gva, trapnr);
/*
* sgx_virt_einit() returns -EINVAL when access_ok() fails on @sig_hva,
* @token_hva or @secs_hva. This should never happen as KVM checks host
* addresses at memslot creation. sgx_virt_einit() has already warned
* in this case, so just return.
*/
if (ret < 0)
return ret;
rflags = vmx_get_rflags(vcpu) & ~(X86_EFLAGS_CF | X86_EFLAGS_PF |
X86_EFLAGS_AF | X86_EFLAGS_SF |
X86_EFLAGS_OF);
if (ret)
rflags |= X86_EFLAGS_ZF;
else
rflags &= ~X86_EFLAGS_ZF;
vmx_set_rflags(vcpu, rflags);
kvm_eax_write(vcpu, ret);
return kvm_skip_emulated_instruction(vcpu);
}
static inline bool encls_leaf_enabled_in_guest(struct kvm_vcpu *vcpu, u32 leaf)
{
/*
* ENCLS generates a #UD if SGX1 isn't supported, i.e. this point will
* be reached if and only if the SGX1 leafs are enabled.
*/
if (leaf >= ECREATE && leaf <= ETRACK)
return true;
if (leaf >= EAUG && leaf <= EMODT)
return guest_cpu_cap_has(vcpu, X86_FEATURE_SGX2);
return false;
}
static inline bool sgx_enabled_in_guest_bios(struct kvm_vcpu *vcpu)
{
const u64 bits = FEAT_CTL_SGX_ENABLED | FEAT_CTL_LOCKED;
return (to_vmx(vcpu)->msr_ia32_feature_control & bits) == bits;
}
int handle_encls(struct kvm_vcpu *vcpu)
{
u32 leaf = kvm_eax_read(vcpu);
if (!enable_sgx || !guest_cpu_cap_has(vcpu, X86_FEATURE_SGX) ||
!guest_cpu_cap_has(vcpu, X86_FEATURE_SGX1)) {
kvm_queue_exception(vcpu, UD_VECTOR);
} else if (!encls_leaf_enabled_in_guest(vcpu, leaf) ||
!sgx_enabled_in_guest_bios(vcpu) || !is_paging(vcpu)) {
kvm_inject_gp(vcpu, 0);
} else {
if (leaf == ECREATE)
return handle_encls_ecreate(vcpu);
if (leaf == EINIT)
return handle_encls_einit(vcpu);
WARN_ONCE(1, "unexpected exit on ENCLS[%u]", leaf);
vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
vcpu->run->hw.hardware_exit_reason = EXIT_REASON_ENCLS;
return 0;
}
return 1;
}
void setup_default_sgx_lepubkeyhash(void)
{
/*
* Use Intel's default value for Skylake hardware if Launch Control is
* not supported, i.e. Intel's hash is hardcoded into silicon, or if
* Launch Control is supported and enabled, i.e. mimic the reset value
* and let the guest write the MSRs at will. If Launch Control is
* supported but disabled, then use the current MSR values as the hash
* MSRs exist but are read-only (locked and not writable).
*/
if (!enable_sgx || boot_cpu_has(X86_FEATURE_SGX_LC) ||
rdmsrq_safe(MSR_IA32_SGXLEPUBKEYHASH0, &sgx_pubkey_hash[0])) {
sgx_pubkey_hash[0] = 0xa6053e051270b7acULL;
sgx_pubkey_hash[1] = 0x6cfbe8ba8b3b413dULL;
sgx_pubkey_hash[2] = 0xc4916d99f2b3735dULL;
sgx_pubkey_hash[3] = 0xd4f8c05909f9bb3bULL;
} else {
/* MSR_IA32_SGXLEPUBKEYHASH0 is read above */
rdmsrq(MSR_IA32_SGXLEPUBKEYHASH1, sgx_pubkey_hash[1]);
rdmsrq(MSR_IA32_SGXLEPUBKEYHASH2, sgx_pubkey_hash[2]);
rdmsrq(MSR_IA32_SGXLEPUBKEYHASH3, sgx_pubkey_hash[3]);
}
}
void vcpu_setup_sgx_lepubkeyhash(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
memcpy(vmx->msr_ia32_sgxlepubkeyhash, sgx_pubkey_hash,
sizeof(sgx_pubkey_hash));
}
/*
* ECREATE must be intercepted to enforce MISCSELECT, ATTRIBUTES and XFRM
* restrictions if the guest's allowed-1 settings diverge from hardware.
*/
static bool sgx_intercept_encls_ecreate(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *guest_cpuid;
u32 eax, ebx, ecx, edx;
if (!vcpu->kvm->arch.sgx_provisioning_allowed)
return true;
guest_cpuid = kvm_find_cpuid_entry_index(vcpu, 0x12, 0);
if (!guest_cpuid)
return true;
cpuid_count(0x12, 0, &eax, &ebx, &ecx, &edx);
if (guest_cpuid->ebx != ebx || guest_cpuid->edx != edx)
return true;
guest_cpuid = kvm_find_cpuid_entry_index(vcpu, 0x12, 1);
if (!guest_cpuid)
return true;
cpuid_count(0x12, 1, &eax, &ebx, &ecx, &edx);
if (guest_cpuid->eax != eax || guest_cpuid->ebx != ebx ||
guest_cpuid->ecx != ecx || guest_cpuid->edx != edx)
return true;
return false;
}
void vmx_write_encls_bitmap(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
{
/*
* There is no software enable bit for SGX that is virtualized by
* hardware, e.g. there's no CR4.SGXE, so when SGX is disabled in the
* guest (either by the host or by the guest's BIOS) but enabled in the
* host, trap all ENCLS leafs and inject #UD/#GP as needed to emulate
* the expected system behavior for ENCLS.
*/
u64 bitmap = -1ull;
/* Nothing to do if hardware doesn't support SGX */
if (!cpu_has_vmx_encls_vmexit())
return;
if (guest_cpu_cap_has(vcpu, X86_FEATURE_SGX) &&
sgx_enabled_in_guest_bios(vcpu)) {
if (guest_cpu_cap_has(vcpu, X86_FEATURE_SGX1)) {
bitmap &= ~GENMASK_ULL(ETRACK, ECREATE);
if (sgx_intercept_encls_ecreate(vcpu))
bitmap |= (1 << ECREATE);
}
if (guest_cpu_cap_has(vcpu, X86_FEATURE_SGX2))
bitmap &= ~GENMASK_ULL(EMODT, EAUG);
/*
* Trap and execute EINIT if launch control is enabled in the
* host using the guest's values for launch control MSRs, even
* if the guest's values are fixed to hardware default values.
* The MSRs are not loaded/saved on VM-Enter/VM-Exit as writing
* the MSRs is extraordinarily expensive.
*/
if (boot_cpu_has(X86_FEATURE_SGX_LC))
bitmap |= (1 << EINIT);
if (!vmcs12 && is_guest_mode(vcpu))
vmcs12 = get_vmcs12(vcpu);
if (vmcs12 && nested_cpu_has_encls_exit(vmcs12))
bitmap |= vmcs12->encls_exiting_bitmap;
}
vmcs_write64(ENCLS_EXITING_BITMAP, bitmap);
}
+34
View File
@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_SGX_H
#define __KVM_X86_SGX_H
#include <linux/kvm_host.h>
#include "capabilities.h"
#include "vmx_ops.h"
#ifdef CONFIG_X86_SGX_KVM
extern bool __read_mostly enable_sgx;
int handle_encls(struct kvm_vcpu *vcpu);
void setup_default_sgx_lepubkeyhash(void);
void vcpu_setup_sgx_lepubkeyhash(struct kvm_vcpu *vcpu);
void vmx_write_encls_bitmap(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12);
#else
#define enable_sgx 0
static inline void setup_default_sgx_lepubkeyhash(void) { }
static inline void vcpu_setup_sgx_lepubkeyhash(struct kvm_vcpu *vcpu) { }
static inline void vmx_write_encls_bitmap(struct kvm_vcpu *vcpu,
struct vmcs12 *vmcs12)
{
/* Nothing to do if hardware doesn't support SGX */
if (cpu_has_vmx_encls_vmexit())
vmcs_write64(ENCLS_EXITING_BITMAP, -1ull);
}
#endif
#endif /* __KVM_X86_SGX_H */
File diff suppressed because it is too large Load Diff
+203
View File
@@ -0,0 +1,203 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_TDX_H
#define __KVM_X86_VMX_TDX_H
#include "tdx_arch.h"
#ifdef CONFIG_KVM_INTEL_TDX
#include "common.h"
int tdx_hardware_setup(void);
void tdx_hardware_unsetup(void);
extern bool enable_tdx;
/* TDX module hardware states. These follow the TDX module OP_STATEs. */
enum kvm_tdx_state {
TD_STATE_UNINITIALIZED = 0,
TD_STATE_INITIALIZED,
TD_STATE_RUNNABLE,
};
struct kvm_tdx {
struct kvm kvm;
struct misc_cg *misc_cg;
int hkid;
enum kvm_tdx_state state;
u64 attributes;
u64 xfam;
u64 tsc_offset;
u64 tsc_multiplier;
struct tdx_td td;
/*
* Scratch pointer used to pass the source page to tdx_mem_page_add().
* Protected by slots_lock, and non-NULL only when mapping a private
* pfn via tdx_gmem_post_populate().
*/
struct page *page_add_src;
/*
* Prevent vCPUs from TD entry to ensure SEPT zap related SEAMCALLs do
* not contend with tdh_vp_enter() and TDCALLs.
* Set/unset is protected with kvm->mmu_lock.
*/
bool wait_for_sept_zap;
};
/* TDX module vCPU states */
enum vcpu_tdx_state {
VCPU_TD_STATE_UNINITIALIZED = 0,
VCPU_TD_STATE_INITIALIZED,
};
struct vcpu_tdx {
struct kvm_vcpu vcpu;
struct vcpu_vt vt;
u64 ext_exit_qualification;
gpa_t exit_gpa;
struct tdx_module_args vp_enter_args;
struct tdx_vp vp;
struct list_head cpu_list;
u64 vp_enter_ret;
enum vcpu_tdx_state state;
u64 map_gpa_next;
u64 map_gpa_end;
};
void tdh_vp_rd_failed(struct vcpu_tdx *tdx, char *uclass, u32 field, u64 err);
void tdh_vp_wr_failed(struct vcpu_tdx *tdx, char *uclass, char *op, u32 field,
u64 val, u64 err);
static __always_inline u64 td_tdcs_exec_read64(struct kvm_tdx *kvm_tdx, u32 field)
{
u64 err, data;
err = tdh_mng_rd(&kvm_tdx->td, TDCS_EXEC(field), &data);
if (unlikely(err)) {
pr_err("TDH_MNG_RD[EXEC.0x%x] failed: 0x%llx\n", field, err);
return 0;
}
return data;
}
static __always_inline void tdvps_vmcs_check(u32 field, u8 bits)
{
#define VMCS_ENC_ACCESS_TYPE_MASK 0x1UL
#define VMCS_ENC_ACCESS_TYPE_FULL 0x0UL
#define VMCS_ENC_ACCESS_TYPE_HIGH 0x1UL
#define VMCS_ENC_ACCESS_TYPE(field) ((field) & VMCS_ENC_ACCESS_TYPE_MASK)
/* TDX is 64bit only. HIGH field isn't supported. */
BUILD_BUG_ON_MSG(__builtin_constant_p(field) &&
VMCS_ENC_ACCESS_TYPE(field) == VMCS_ENC_ACCESS_TYPE_HIGH,
"Read/Write to TD VMCS *_HIGH fields not supported");
BUILD_BUG_ON(bits != 16 && bits != 32 && bits != 64);
#define VMCS_ENC_WIDTH_MASK GENMASK(14, 13)
#define VMCS_ENC_WIDTH_16BIT (0UL << 13)
#define VMCS_ENC_WIDTH_64BIT (1UL << 13)
#define VMCS_ENC_WIDTH_32BIT (2UL << 13)
#define VMCS_ENC_WIDTH_NATURAL (3UL << 13)
#define VMCS_ENC_WIDTH(field) ((field) & VMCS_ENC_WIDTH_MASK)
/* TDX is 64bit only. i.e. natural width = 64bit. */
BUILD_BUG_ON_MSG(bits != 64 && __builtin_constant_p(field) &&
(VMCS_ENC_WIDTH(field) == VMCS_ENC_WIDTH_64BIT ||
VMCS_ENC_WIDTH(field) == VMCS_ENC_WIDTH_NATURAL),
"Invalid TD VMCS access for 64-bit field");
BUILD_BUG_ON_MSG(bits != 32 && __builtin_constant_p(field) &&
VMCS_ENC_WIDTH(field) == VMCS_ENC_WIDTH_32BIT,
"Invalid TD VMCS access for 32-bit field");
BUILD_BUG_ON_MSG(bits != 16 && __builtin_constant_p(field) &&
VMCS_ENC_WIDTH(field) == VMCS_ENC_WIDTH_16BIT,
"Invalid TD VMCS access for 16-bit field");
}
static __always_inline void tdvps_management_check(u64 field, u8 bits) {}
static __always_inline void tdvps_state_non_arch_check(u64 field, u8 bits) {}
#define TDX_BUILD_TDVPS_ACCESSORS(bits, uclass, lclass) \
static __always_inline u##bits td_##lclass##_read##bits(struct vcpu_tdx *tdx, \
u32 field) \
{ \
u64 err, data; \
\
tdvps_##lclass##_check(field, bits); \
err = tdh_vp_rd(&tdx->vp, TDVPS_##uclass(field), &data); \
if (unlikely(err)) { \
tdh_vp_rd_failed(tdx, #uclass, field, err); \
return 0; \
} \
return (u##bits)data; \
} \
static __always_inline void td_##lclass##_write##bits(struct vcpu_tdx *tdx, \
u32 field, u##bits val) \
{ \
u64 err; \
\
tdvps_##lclass##_check(field, bits); \
err = tdh_vp_wr(&tdx->vp, TDVPS_##uclass(field), val, \
GENMASK_ULL(bits - 1, 0)); \
if (unlikely(err)) \
tdh_vp_wr_failed(tdx, #uclass, " = ", field, (u64)val, err); \
} \
static __always_inline void td_##lclass##_setbit##bits(struct vcpu_tdx *tdx, \
u32 field, u64 bit) \
{ \
u64 err; \
\
tdvps_##lclass##_check(field, bits); \
err = tdh_vp_wr(&tdx->vp, TDVPS_##uclass(field), bit, bit); \
if (unlikely(err)) \
tdh_vp_wr_failed(tdx, #uclass, " |= ", field, bit, err); \
} \
static __always_inline void td_##lclass##_clearbit##bits(struct vcpu_tdx *tdx, \
u32 field, u64 bit) \
{ \
u64 err; \
\
tdvps_##lclass##_check(field, bits); \
err = tdh_vp_wr(&tdx->vp, TDVPS_##uclass(field), 0, bit); \
if (unlikely(err)) \
tdh_vp_wr_failed(tdx, #uclass, " &= ~", field, bit, err);\
}
bool tdx_interrupt_allowed(struct kvm_vcpu *vcpu);
int tdx_complete_emulated_msr(struct kvm_vcpu *vcpu, int err);
TDX_BUILD_TDVPS_ACCESSORS(16, VMCS, vmcs);
TDX_BUILD_TDVPS_ACCESSORS(32, VMCS, vmcs);
TDX_BUILD_TDVPS_ACCESSORS(64, VMCS, vmcs);
TDX_BUILD_TDVPS_ACCESSORS(8, MANAGEMENT, management);
TDX_BUILD_TDVPS_ACCESSORS(64, STATE_NON_ARCH, state_non_arch);
#else
#define enable_tdx 0
struct kvm_tdx {
struct kvm kvm;
};
struct vcpu_tdx {
struct kvm_vcpu vcpu;
};
static inline bool tdx_interrupt_allowed(struct kvm_vcpu *vcpu) { return false; }
static inline int tdx_complete_emulated_msr(struct kvm_vcpu *vcpu, int err) { return 0; }
#endif
#endif
+161
View File
@@ -0,0 +1,161 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* architectural constants/data definitions for TDX SEAMCALLs */
#ifndef __KVM_X86_TDX_ARCH_H
#define __KVM_X86_TDX_ARCH_H
#include <linux/types.h>
/* TDX control structure (TDR/TDCS/TDVPS) field access codes */
#define TDX_NON_ARCH BIT_ULL(63)
#define TDX_CLASS_SHIFT 56
#define TDX_FIELD_MASK GENMASK_ULL(31, 0)
#define __BUILD_TDX_FIELD(non_arch, class, field) \
(((non_arch) ? TDX_NON_ARCH : 0) | \
((u64)(class) << TDX_CLASS_SHIFT) | \
((u64)(field) & TDX_FIELD_MASK))
#define BUILD_TDX_FIELD(class, field) \
__BUILD_TDX_FIELD(false, (class), (field))
#define BUILD_TDX_FIELD_NON_ARCH(class, field) \
__BUILD_TDX_FIELD(true, (class), (field))
/* Class code for TD */
#define TD_CLASS_EXECUTION_CONTROLS 17ULL
/* Class code for TDVPS */
#define TDVPS_CLASS_VMCS 0ULL
#define TDVPS_CLASS_GUEST_GPR 16ULL
#define TDVPS_CLASS_OTHER_GUEST 17ULL
#define TDVPS_CLASS_MANAGEMENT 32ULL
enum tdx_tdcs_execution_control {
TD_TDCS_EXEC_TSC_OFFSET = 10,
TD_TDCS_EXEC_TSC_MULTIPLIER = 11,
};
enum tdx_vcpu_guest_other_state {
TD_VCPU_STATE_DETAILS_NON_ARCH = 0x100,
};
#define TDX_VCPU_STATE_DETAILS_INTR_PENDING BIT_ULL(0)
static inline bool tdx_vcpu_state_details_intr_pending(u64 vcpu_state_details)
{
return !!(vcpu_state_details & TDX_VCPU_STATE_DETAILS_INTR_PENDING);
}
/* @field is any of enum tdx_tdcs_execution_control */
#define TDCS_EXEC(field) BUILD_TDX_FIELD(TD_CLASS_EXECUTION_CONTROLS, (field))
/* @field is the VMCS field encoding */
#define TDVPS_VMCS(field) BUILD_TDX_FIELD(TDVPS_CLASS_VMCS, (field))
/* @field is any of enum tdx_guest_other_state */
#define TDVPS_STATE(field) BUILD_TDX_FIELD(TDVPS_CLASS_OTHER_GUEST, (field))
#define TDVPS_STATE_NON_ARCH(field) BUILD_TDX_FIELD_NON_ARCH(TDVPS_CLASS_OTHER_GUEST, (field))
/* Management class fields */
enum tdx_vcpu_guest_management {
TD_VCPU_PEND_NMI = 11,
};
/* @field is any of enum tdx_vcpu_guest_management */
#define TDVPS_MANAGEMENT(field) BUILD_TDX_FIELD(TDVPS_CLASS_MANAGEMENT, (field))
#define TDX_EXTENDMR_CHUNKSIZE 256
struct tdx_cpuid_value {
u32 eax;
u32 ebx;
u32 ecx;
u32 edx;
} __packed;
#define TDX_EXT_EXIT_QUAL_TYPE_MASK GENMASK(3, 0)
#define TDX_EXT_EXIT_QUAL_TYPE_PENDING_EPT_VIOLATION 6
/*
* TD_PARAMS is provided as an input to TDH_MNG_INIT, the size of which is 1024B.
*/
struct td_params {
u64 attributes;
u64 xfam;
u16 max_vcpus;
u8 reserved0[6];
u64 eptp_controls;
u64 config_flags;
u16 tsc_frequency;
u8 reserved1[38];
u64 mrconfigid[6];
u64 mrowner[6];
u64 mrownerconfig[6];
u64 reserved2[4];
union {
DECLARE_FLEX_ARRAY(struct tdx_cpuid_value, cpuid_values);
u8 reserved3[768];
};
} __packed __aligned(1024);
/*
* Guest uses MAX_PA for GPAW when set.
* 0: GPA.SHARED bit is GPA[47]
* 1: GPA.SHARED bit is GPA[51]
*/
#define TDX_CONFIG_FLAGS_MAX_GPAW BIT_ULL(0)
/*
* TDH.VP.ENTER, TDG.VP.VMCALL preserves RBP
* 0: RBP can be used for TDG.VP.VMCALL input. RBP is clobbered.
* 1: RBP can't be used for TDG.VP.VMCALL input. RBP is preserved.
*/
#define TDX_CONFIG_FLAGS_NO_RBP_MOD BIT_ULL(2)
/*
* TDX requires the frequency to be defined in units of 25MHz, which is the
* frequency of the core crystal clock on TDX-capable platforms, i.e. the TDX
* module can only program frequencies that are multiples of 25MHz. The
* frequency must be between 100mhz and 10ghz (inclusive).
*/
#define TDX_TSC_KHZ_TO_25MHZ(tsc_in_khz) ((tsc_in_khz) / (25 * 1000))
#define TDX_TSC_25MHZ_TO_KHZ(tsc_in_25mhz) ((tsc_in_25mhz) * (25 * 1000))
#define TDX_MIN_TSC_FREQUENCY_KHZ (100 * 1000)
#define TDX_MAX_TSC_FREQUENCY_KHZ (10 * 1000 * 1000)
/* Additional Secure EPT entry information */
#define TDX_SEPT_LEVEL_MASK GENMASK_ULL(2, 0)
#define TDX_SEPT_STATE_MASK GENMASK_ULL(15, 8)
#define TDX_SEPT_STATE_SHIFT 8
enum tdx_sept_entry_state {
TDX_SEPT_FREE = 0,
TDX_SEPT_BLOCKED = 1,
TDX_SEPT_PENDING = 2,
TDX_SEPT_PENDING_BLOCKED = 3,
TDX_SEPT_PRESENT = 4,
};
static inline u8 tdx_get_sept_level(u64 sept_entry_info)
{
return sept_entry_info & TDX_SEPT_LEVEL_MASK;
}
static inline u8 tdx_get_sept_state(u64 sept_entry_info)
{
return (sept_entry_info & TDX_SEPT_STATE_MASK) >> TDX_SEPT_STATE_SHIFT;
}
#define MD_FIELD_ID_FEATURES0_TOPOLOGY_ENUM BIT_ULL(20)
/*
* TD scope metadata field ID.
*/
#define TD_MD_FIELD_ID_CPUID_VALUES 0x9410000300000000ULL
#endif /* __KVM_X86_TDX_ARCH_H */
+196
View File
@@ -0,0 +1,196 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_VMCS_H
#define __KVM_X86_VMX_VMCS_H
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/nospec.h>
#include <asm/kvm.h>
#include <asm/vmx.h>
#include "capabilities.h"
/*
* Indexing into the vmcs12 uses the VMCS encoding rotated left by 6 as a very
* rudimentary compression of the range of indices. The compression ratio is
* good enough to allow KVM to use a (very sparsely populated) array without
* wasting too much memory, while the "algorithm" is fast enough to be used to
* lookup vmcs12 fields on-demand, e.g. for emulation.
*/
#define ROL16(val, n) ((u16)(((u16)(val) << (n)) | ((u16)(val) >> (16 - (n)))))
#define VMCS12_IDX_TO_ENC(idx) ROL16(idx, 10)
#define ENC_TO_VMCS12_IDX(enc) ROL16(enc, 6)
DECLARE_PER_CPU(struct vmcs *, current_vmcs);
/*
* vmcs_host_state tracks registers that are loaded from the VMCS on VMEXIT
* and whose values change infrequently, but are not constant. I.e. this is
* used as a write-through cache of the corresponding VMCS fields.
*/
struct vmcs_host_state {
unsigned long cr3; /* May not match real cr3 */
unsigned long cr4; /* May not match real cr4 */
unsigned long gs_base;
unsigned long fs_base;
unsigned long rsp;
u16 fs_sel, gs_sel, ldt_sel;
#ifdef CONFIG_X86_64
u16 ds_sel, es_sel;
#endif
};
struct vmcs_controls_shadow {
u32 vm_entry;
u32 vm_exit;
u32 pin;
u32 exec;
u32 secondary_exec;
u64 tertiary_exec;
};
/*
* Track a VMCS that may be loaded on a certain CPU. If it is (cpu!=-1), also
* remember whether it was VMLAUNCHed, and maintain a linked list of all VMCSs
* loaded on this CPU (so we can clear them if the CPU goes down).
*/
struct loaded_vmcs {
struct vmcs *vmcs;
struct vmcs *shadow_vmcs;
int cpu;
bool launched;
bool nmi_known_unmasked;
bool hv_timer_soft_disabled;
/* Support for vnmi-less CPUs */
int soft_vnmi_blocked;
ktime_t entry_time;
s64 vnmi_blocked_time;
unsigned long *msr_bitmap;
struct list_head loaded_vmcss_on_cpu_link;
struct vmcs_host_state host_state;
struct vmcs_controls_shadow controls_shadow;
};
static __always_inline bool is_intr_type(u32 intr_info, u32 type)
{
const u32 mask = INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK;
return (intr_info & mask) == (INTR_INFO_VALID_MASK | type);
}
static inline bool is_intr_type_n(u32 intr_info, u32 type, u8 vector)
{
const u32 mask = INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK |
INTR_INFO_VECTOR_MASK;
return (intr_info & mask) == (INTR_INFO_VALID_MASK | type | vector);
}
static inline bool is_exception_n(u32 intr_info, u8 vector)
{
return is_intr_type_n(intr_info, INTR_TYPE_HARD_EXCEPTION, vector);
}
static inline bool is_debug(u32 intr_info)
{
return is_exception_n(intr_info, DB_VECTOR);
}
static inline bool is_breakpoint(u32 intr_info)
{
return is_exception_n(intr_info, BP_VECTOR);
}
static inline bool is_double_fault(u32 intr_info)
{
return is_exception_n(intr_info, DF_VECTOR);
}
static inline bool is_page_fault(u32 intr_info)
{
return is_exception_n(intr_info, PF_VECTOR);
}
static inline bool is_invalid_opcode(u32 intr_info)
{
return is_exception_n(intr_info, UD_VECTOR);
}
static inline bool is_gp_fault(u32 intr_info)
{
return is_exception_n(intr_info, GP_VECTOR);
}
static inline bool is_alignment_check(u32 intr_info)
{
return is_exception_n(intr_info, AC_VECTOR);
}
static inline bool is_machine_check(u32 intr_info)
{
return is_exception_n(intr_info, MC_VECTOR);
}
static inline bool is_nm_fault(u32 intr_info)
{
return is_exception_n(intr_info, NM_VECTOR);
}
static inline bool is_ve_fault(u32 intr_info)
{
return is_exception_n(intr_info, VE_VECTOR);
}
/* Undocumented: icebp/int1 */
static inline bool is_icebp(u32 intr_info)
{
return is_intr_type(intr_info, INTR_TYPE_PRIV_SW_EXCEPTION);
}
static __always_inline bool is_nmi(u32 intr_info)
{
return is_intr_type(intr_info, INTR_TYPE_NMI_INTR);
}
static inline bool is_external_intr(u32 intr_info)
{
return is_intr_type(intr_info, INTR_TYPE_EXT_INTR);
}
static inline bool is_exception_with_error_code(u32 intr_info)
{
const u32 mask = INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK;
return (intr_info & mask) == mask;
}
enum vmcs_field_width {
VMCS_FIELD_WIDTH_U16 = 0,
VMCS_FIELD_WIDTH_U64 = 1,
VMCS_FIELD_WIDTH_U32 = 2,
VMCS_FIELD_WIDTH_NATURAL_WIDTH = 3
};
static inline int vmcs_field_width(unsigned long field)
{
if (0x1 & field) /* the *_HIGH fields are all 32 bit */
return VMCS_FIELD_WIDTH_U32;
return (field >> 13) & 0x3;
}
static inline int vmcs_field_readonly(unsigned long field)
{
return (((field >> 10) & 0x3) == 1);
}
#define VMCS_FIELD_INDEX_SHIFT (1)
#define VMCS_FIELD_INDEX_MASK GENMASK(9, 1)
static inline unsigned int vmcs_field_index(unsigned long field)
{
return (field & VMCS_FIELD_INDEX_MASK) >> VMCS_FIELD_INDEX_SHIFT;
}
#endif /* __KVM_X86_VMX_VMCS_H */
+227
View File
@@ -0,0 +1,227 @@
// SPDX-License-Identifier: GPL-2.0
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "vmcs12.h"
#define VMCS12_OFFSET(x) offsetof(struct vmcs12, x)
#define FIELD(number, name) [ENC_TO_VMCS12_IDX(number)] = VMCS12_OFFSET(name)
#define FIELD64(number, name) \
FIELD(number, name), \
[ENC_TO_VMCS12_IDX(number##_HIGH)] = VMCS12_OFFSET(name) + sizeof(u32)
static const u16 kvm_supported_vmcs12_field_offsets[] __initconst = {
FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id),
FIELD(POSTED_INTR_NV, posted_intr_nv),
FIELD(GUEST_ES_SELECTOR, guest_es_selector),
FIELD(GUEST_CS_SELECTOR, guest_cs_selector),
FIELD(GUEST_SS_SELECTOR, guest_ss_selector),
FIELD(GUEST_DS_SELECTOR, guest_ds_selector),
FIELD(GUEST_FS_SELECTOR, guest_fs_selector),
FIELD(GUEST_GS_SELECTOR, guest_gs_selector),
FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector),
FIELD(GUEST_TR_SELECTOR, guest_tr_selector),
FIELD(GUEST_INTR_STATUS, guest_intr_status),
FIELD(GUEST_PML_INDEX, guest_pml_index),
FIELD(HOST_ES_SELECTOR, host_es_selector),
FIELD(HOST_CS_SELECTOR, host_cs_selector),
FIELD(HOST_SS_SELECTOR, host_ss_selector),
FIELD(HOST_DS_SELECTOR, host_ds_selector),
FIELD(HOST_FS_SELECTOR, host_fs_selector),
FIELD(HOST_GS_SELECTOR, host_gs_selector),
FIELD(HOST_TR_SELECTOR, host_tr_selector),
FIELD64(IO_BITMAP_A, io_bitmap_a),
FIELD64(IO_BITMAP_B, io_bitmap_b),
FIELD64(MSR_BITMAP, msr_bitmap),
FIELD64(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr),
FIELD64(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr),
FIELD64(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr),
FIELD64(PML_ADDRESS, pml_address),
FIELD64(TSC_OFFSET, tsc_offset),
FIELD64(TSC_MULTIPLIER, tsc_multiplier),
FIELD64(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr),
FIELD64(APIC_ACCESS_ADDR, apic_access_addr),
FIELD64(POSTED_INTR_DESC_ADDR, posted_intr_desc_addr),
FIELD64(VM_FUNCTION_CONTROL, vm_function_control),
FIELD64(EPT_POINTER, ept_pointer),
FIELD64(EOI_EXIT_BITMAP0, eoi_exit_bitmap0),
FIELD64(EOI_EXIT_BITMAP1, eoi_exit_bitmap1),
FIELD64(EOI_EXIT_BITMAP2, eoi_exit_bitmap2),
FIELD64(EOI_EXIT_BITMAP3, eoi_exit_bitmap3),
FIELD64(EPTP_LIST_ADDRESS, eptp_list_address),
FIELD64(VMREAD_BITMAP, vmread_bitmap),
FIELD64(VMWRITE_BITMAP, vmwrite_bitmap),
FIELD64(XSS_EXIT_BITMAP, xss_exit_bitmap),
FIELD64(ENCLS_EXITING_BITMAP, encls_exiting_bitmap),
FIELD64(GUEST_PHYSICAL_ADDRESS, guest_physical_address),
FIELD64(VMCS_LINK_POINTER, vmcs_link_pointer),
FIELD64(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl),
FIELD64(GUEST_IA32_PAT, guest_ia32_pat),
FIELD64(GUEST_IA32_EFER, guest_ia32_efer),
FIELD64(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl),
FIELD64(GUEST_PDPTR0, guest_pdptr0),
FIELD64(GUEST_PDPTR1, guest_pdptr1),
FIELD64(GUEST_PDPTR2, guest_pdptr2),
FIELD64(GUEST_PDPTR3, guest_pdptr3),
FIELD64(GUEST_BNDCFGS, guest_bndcfgs),
FIELD64(HOST_IA32_PAT, host_ia32_pat),
FIELD64(HOST_IA32_EFER, host_ia32_efer),
FIELD64(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl),
FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control),
FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control),
FIELD(EXCEPTION_BITMAP, exception_bitmap),
FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask),
FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match),
FIELD(CR3_TARGET_COUNT, cr3_target_count),
FIELD(VM_EXIT_CONTROLS, vm_exit_controls),
FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count),
FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count),
FIELD(VM_ENTRY_CONTROLS, vm_entry_controls),
FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count),
FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field),
FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE, vm_entry_exception_error_code),
FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len),
FIELD(TPR_THRESHOLD, tpr_threshold),
FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control),
FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error),
FIELD(VM_EXIT_REASON, vm_exit_reason),
FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info),
FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code),
FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field),
FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code),
FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len),
FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info),
FIELD(GUEST_ES_LIMIT, guest_es_limit),
FIELD(GUEST_CS_LIMIT, guest_cs_limit),
FIELD(GUEST_SS_LIMIT, guest_ss_limit),
FIELD(GUEST_DS_LIMIT, guest_ds_limit),
FIELD(GUEST_FS_LIMIT, guest_fs_limit),
FIELD(GUEST_GS_LIMIT, guest_gs_limit),
FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit),
FIELD(GUEST_TR_LIMIT, guest_tr_limit),
FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit),
FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit),
FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes),
FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes),
FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes),
FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes),
FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes),
FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes),
FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes),
FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes),
FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info),
FIELD(GUEST_ACTIVITY_STATE, guest_activity_state),
FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs),
FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs),
FIELD(VMX_PREEMPTION_TIMER_VALUE, vmx_preemption_timer_value),
FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask),
FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask),
FIELD(CR0_READ_SHADOW, cr0_read_shadow),
FIELD(CR4_READ_SHADOW, cr4_read_shadow),
FIELD(EXIT_QUALIFICATION, exit_qualification),
FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address),
FIELD(GUEST_CR0, guest_cr0),
FIELD(GUEST_CR3, guest_cr3),
FIELD(GUEST_CR4, guest_cr4),
FIELD(GUEST_ES_BASE, guest_es_base),
FIELD(GUEST_CS_BASE, guest_cs_base),
FIELD(GUEST_SS_BASE, guest_ss_base),
FIELD(GUEST_DS_BASE, guest_ds_base),
FIELD(GUEST_FS_BASE, guest_fs_base),
FIELD(GUEST_GS_BASE, guest_gs_base),
FIELD(GUEST_LDTR_BASE, guest_ldtr_base),
FIELD(GUEST_TR_BASE, guest_tr_base),
FIELD(GUEST_GDTR_BASE, guest_gdtr_base),
FIELD(GUEST_IDTR_BASE, guest_idtr_base),
FIELD(GUEST_DR7, guest_dr7),
FIELD(GUEST_RSP, guest_rsp),
FIELD(GUEST_RIP, guest_rip),
FIELD(GUEST_RFLAGS, guest_rflags),
FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions),
FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp),
FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip),
FIELD(GUEST_S_CET, guest_s_cet),
FIELD(GUEST_SSP, guest_ssp),
FIELD(GUEST_INTR_SSP_TABLE, guest_ssp_tbl),
FIELD(HOST_CR0, host_cr0),
FIELD(HOST_CR3, host_cr3),
FIELD(HOST_CR4, host_cr4),
FIELD(HOST_FS_BASE, host_fs_base),
FIELD(HOST_GS_BASE, host_gs_base),
FIELD(HOST_TR_BASE, host_tr_base),
FIELD(HOST_GDTR_BASE, host_gdtr_base),
FIELD(HOST_IDTR_BASE, host_idtr_base),
FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp),
FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip),
FIELD(HOST_RSP, host_rsp),
FIELD(HOST_RIP, host_rip),
FIELD(HOST_S_CET, host_s_cet),
FIELD(HOST_SSP, host_ssp),
FIELD(HOST_INTR_SSP_TABLE, host_ssp_tbl),
};
u16 vmcs12_field_offsets[ARRAY_SIZE(kvm_supported_vmcs12_field_offsets)] __ro_after_init;
unsigned int nr_vmcs12_fields __ro_after_init;
#define VMCS12_CASE64(enc) case enc##_HIGH: case enc
static __init bool cpu_has_vmcs12_field(unsigned int idx)
{
switch (VMCS12_IDX_TO_ENC(idx)) {
case VIRTUAL_PROCESSOR_ID:
return cpu_has_vmx_vpid();
case POSTED_INTR_NV:
return cpu_has_vmx_posted_intr();
VMCS12_CASE64(TSC_MULTIPLIER):
return cpu_has_vmx_tsc_scaling();
case TPR_THRESHOLD:
VMCS12_CASE64(VIRTUAL_APIC_PAGE_ADDR):
return cpu_has_vmx_tpr_shadow();
VMCS12_CASE64(APIC_ACCESS_ADDR):
return cpu_has_vmx_virtualize_apic_accesses();
VMCS12_CASE64(POSTED_INTR_DESC_ADDR):
return cpu_has_vmx_posted_intr();
case GUEST_INTR_STATUS:
return cpu_has_vmx_virtual_intr_delivery();
VMCS12_CASE64(VM_FUNCTION_CONTROL):
VMCS12_CASE64(EPTP_LIST_ADDRESS):
return cpu_has_vmx_vmfunc();
VMCS12_CASE64(EPT_POINTER):
return cpu_has_vmx_ept();
VMCS12_CASE64(XSS_EXIT_BITMAP):
return cpu_has_vmx_xsaves();
VMCS12_CASE64(ENCLS_EXITING_BITMAP):
return cpu_has_vmx_encls_vmexit();
VMCS12_CASE64(GUEST_IA32_PERF_GLOBAL_CTRL):
VMCS12_CASE64(HOST_IA32_PERF_GLOBAL_CTRL):
return cpu_has_load_perf_global_ctrl();
case SECONDARY_VM_EXEC_CONTROL:
return cpu_has_secondary_exec_ctrls();
case GUEST_S_CET:
case GUEST_SSP:
case GUEST_INTR_SSP_TABLE:
case HOST_S_CET:
case HOST_SSP:
case HOST_INTR_SSP_TABLE:
return cpu_has_load_cet_ctrl();
/* KVM always emulates PML and the VMX preemption timer in software. */
case GUEST_PML_INDEX:
case VMX_PREEMPTION_TIMER_VALUE:
default:
return true;
}
}
void __init nested_vmx_setup_vmcs12_fields(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(kvm_supported_vmcs12_field_offsets); i++) {
if (!kvm_supported_vmcs12_field_offsets[i] ||
!cpu_has_vmcs12_field(i))
continue;
vmcs12_field_offsets[i] = kvm_supported_vmcs12_field_offsets[i];
nr_vmcs12_fields = i + 1;
}
}
+445
View File
@@ -0,0 +1,445 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_VMCS12_H
#define __KVM_X86_VMX_VMCS12_H
#include <linux/build_bug.h>
#include "vmcs.h"
/*
* struct vmcs12 describes the state that our guest hypervisor (L1) keeps for a
* single nested guest (L2), hence the name vmcs12. Any VMX implementation has
* a VMCS structure, and vmcs12 is our emulated VMX's VMCS. This structure is
* stored in guest memory specified by VMPTRLD, but is opaque to the guest,
* which must access it using VMREAD/VMWRITE/VMCLEAR instructions.
* More than one of these structures may exist, if L1 runs multiple L2 guests.
* nested_vmx_run() will use the data here to build the vmcs02: a VMCS for the
* underlying hardware which will be used to run L2.
* This structure is packed to ensure that its layout is identical across
* machines (necessary for live migration).
*
* IMPORTANT: Changing the layout of existing fields in this structure
* will break save/restore compatibility with older kvm releases. When
* adding new fields, either use space in the reserved padding* arrays
* or add the new fields to the end of the structure.
*/
typedef u64 natural_width;
struct __packed vmcs12 {
/* According to the Intel spec, a VMCS region must start with the
* following two fields. Then follow implementation-specific data.
*/
struct vmcs_hdr hdr;
u32 abort;
u32 launch_state; /* set to 0 by VMCLEAR, to 1 by VMLAUNCH */
u32 padding[7]; /* room for future expansion */
u64 io_bitmap_a;
u64 io_bitmap_b;
u64 msr_bitmap;
u64 vm_exit_msr_store_addr;
u64 vm_exit_msr_load_addr;
u64 vm_entry_msr_load_addr;
u64 tsc_offset;
u64 virtual_apic_page_addr;
u64 apic_access_addr;
u64 posted_intr_desc_addr;
u64 ept_pointer;
u64 eoi_exit_bitmap0;
u64 eoi_exit_bitmap1;
u64 eoi_exit_bitmap2;
u64 eoi_exit_bitmap3;
u64 xss_exit_bitmap;
u64 guest_physical_address;
u64 vmcs_link_pointer;
u64 guest_ia32_debugctl;
u64 guest_ia32_pat;
u64 guest_ia32_efer;
u64 guest_ia32_perf_global_ctrl;
u64 guest_pdptr0;
u64 guest_pdptr1;
u64 guest_pdptr2;
u64 guest_pdptr3;
u64 guest_bndcfgs;
u64 host_ia32_pat;
u64 host_ia32_efer;
u64 host_ia32_perf_global_ctrl;
u64 vmread_bitmap;
u64 vmwrite_bitmap;
u64 vm_function_control;
u64 eptp_list_address;
u64 pml_address;
u64 encls_exiting_bitmap;
u64 tsc_multiplier;
u64 padding64[1]; /* room for future expansion */
/*
* To allow migration of L1 (complete with its L2 guests) between
* machines of different natural widths (32 or 64 bit), we cannot have
* unsigned long fields with no explicit size. We use u64 (aliased
* natural_width) instead. Luckily, x86 is little-endian.
*/
natural_width cr0_guest_host_mask;
natural_width cr4_guest_host_mask;
natural_width cr0_read_shadow;
natural_width cr4_read_shadow;
natural_width dead_space[4]; /* Last remnants of cr3_target_value[0-3]. */
natural_width exit_qualification;
natural_width guest_linear_address;
natural_width guest_cr0;
natural_width guest_cr3;
natural_width guest_cr4;
natural_width guest_es_base;
natural_width guest_cs_base;
natural_width guest_ss_base;
natural_width guest_ds_base;
natural_width guest_fs_base;
natural_width guest_gs_base;
natural_width guest_ldtr_base;
natural_width guest_tr_base;
natural_width guest_gdtr_base;
natural_width guest_idtr_base;
natural_width guest_dr7;
natural_width guest_rsp;
natural_width guest_rip;
natural_width guest_rflags;
natural_width guest_pending_dbg_exceptions;
natural_width guest_sysenter_esp;
natural_width guest_sysenter_eip;
natural_width host_cr0;
natural_width host_cr3;
natural_width host_cr4;
natural_width host_fs_base;
natural_width host_gs_base;
natural_width host_tr_base;
natural_width host_gdtr_base;
natural_width host_idtr_base;
natural_width host_ia32_sysenter_esp;
natural_width host_ia32_sysenter_eip;
natural_width host_rsp;
natural_width host_rip;
natural_width host_s_cet;
natural_width host_ssp;
natural_width host_ssp_tbl;
natural_width guest_s_cet;
natural_width guest_ssp;
natural_width guest_ssp_tbl;
natural_width paddingl[2]; /* room for future expansion */
u32 pin_based_vm_exec_control;
u32 cpu_based_vm_exec_control;
u32 exception_bitmap;
u32 page_fault_error_code_mask;
u32 page_fault_error_code_match;
u32 cr3_target_count;
u32 vm_exit_controls;
u32 vm_exit_msr_store_count;
u32 vm_exit_msr_load_count;
u32 vm_entry_controls;
u32 vm_entry_msr_load_count;
u32 vm_entry_intr_info_field;
u32 vm_entry_exception_error_code;
u32 vm_entry_instruction_len;
u32 tpr_threshold;
u32 secondary_vm_exec_control;
u32 vm_instruction_error;
u32 vm_exit_reason;
u32 vm_exit_intr_info;
u32 vm_exit_intr_error_code;
u32 idt_vectoring_info_field;
u32 idt_vectoring_error_code;
u32 vm_exit_instruction_len;
u32 vmx_instruction_info;
u32 guest_es_limit;
u32 guest_cs_limit;
u32 guest_ss_limit;
u32 guest_ds_limit;
u32 guest_fs_limit;
u32 guest_gs_limit;
u32 guest_ldtr_limit;
u32 guest_tr_limit;
u32 guest_gdtr_limit;
u32 guest_idtr_limit;
u32 guest_es_ar_bytes;
u32 guest_cs_ar_bytes;
u32 guest_ss_ar_bytes;
u32 guest_ds_ar_bytes;
u32 guest_fs_ar_bytes;
u32 guest_gs_ar_bytes;
u32 guest_ldtr_ar_bytes;
u32 guest_tr_ar_bytes;
u32 guest_interruptibility_info;
u32 guest_activity_state;
u32 guest_sysenter_cs;
u32 host_ia32_sysenter_cs;
u32 vmx_preemption_timer_value;
u32 padding32[7]; /* room for future expansion */
u16 virtual_processor_id;
u16 posted_intr_nv;
u16 guest_es_selector;
u16 guest_cs_selector;
u16 guest_ss_selector;
u16 guest_ds_selector;
u16 guest_fs_selector;
u16 guest_gs_selector;
u16 guest_ldtr_selector;
u16 guest_tr_selector;
u16 guest_intr_status;
u16 host_es_selector;
u16 host_cs_selector;
u16 host_ss_selector;
u16 host_ds_selector;
u16 host_fs_selector;
u16 host_gs_selector;
u16 host_tr_selector;
u16 guest_pml_index;
};
/*
* VMCS12_REVISION is KVM's arbitrary ID for the layout of struct vmcs12. KVM
* enumerates this value to L1 via MSR_IA32_VMX_BASIC, and checks the revision
* ID during nested VMPTRLD to verify that L1 is loading a VMCS that adhere's
* to KVM's virtual CPU definition.
*
* DO NOT change this value, as it will break save/restore compatibility with
* older KVM releases.
*/
#define VMCS12_REVISION 0x11e57ed0
/*
* VMCS12_SIZE is the number of bytes L1 should allocate for the VMXON region
* and any VMCS region. Although only sizeof(struct vmcs12) are used by the
* current implementation, 4K are reserved to avoid future complications and
* to preserve userspace ABI.
*/
#define VMCS12_SIZE KVM_STATE_NESTED_VMX_VMCS_SIZE
/*
* For save/restore compatibility, the vmcs12 field offsets must not change,
* although appending fields and/or filling gaps is obviously allowed.
*/
#define CHECK_OFFSET(field, loc) \
ASSERT_STRUCT_OFFSET(struct vmcs12, field, loc)
static inline void vmx_check_vmcs12_offsets(void)
{
CHECK_OFFSET(hdr, 0);
CHECK_OFFSET(abort, 4);
CHECK_OFFSET(launch_state, 8);
CHECK_OFFSET(io_bitmap_a, 40);
CHECK_OFFSET(io_bitmap_b, 48);
CHECK_OFFSET(msr_bitmap, 56);
CHECK_OFFSET(vm_exit_msr_store_addr, 64);
CHECK_OFFSET(vm_exit_msr_load_addr, 72);
CHECK_OFFSET(vm_entry_msr_load_addr, 80);
CHECK_OFFSET(tsc_offset, 88);
CHECK_OFFSET(virtual_apic_page_addr, 96);
CHECK_OFFSET(apic_access_addr, 104);
CHECK_OFFSET(posted_intr_desc_addr, 112);
CHECK_OFFSET(ept_pointer, 120);
CHECK_OFFSET(eoi_exit_bitmap0, 128);
CHECK_OFFSET(eoi_exit_bitmap1, 136);
CHECK_OFFSET(eoi_exit_bitmap2, 144);
CHECK_OFFSET(eoi_exit_bitmap3, 152);
CHECK_OFFSET(xss_exit_bitmap, 160);
CHECK_OFFSET(guest_physical_address, 168);
CHECK_OFFSET(vmcs_link_pointer, 176);
CHECK_OFFSET(guest_ia32_debugctl, 184);
CHECK_OFFSET(guest_ia32_pat, 192);
CHECK_OFFSET(guest_ia32_efer, 200);
CHECK_OFFSET(guest_ia32_perf_global_ctrl, 208);
CHECK_OFFSET(guest_pdptr0, 216);
CHECK_OFFSET(guest_pdptr1, 224);
CHECK_OFFSET(guest_pdptr2, 232);
CHECK_OFFSET(guest_pdptr3, 240);
CHECK_OFFSET(guest_bndcfgs, 248);
CHECK_OFFSET(host_ia32_pat, 256);
CHECK_OFFSET(host_ia32_efer, 264);
CHECK_OFFSET(host_ia32_perf_global_ctrl, 272);
CHECK_OFFSET(vmread_bitmap, 280);
CHECK_OFFSET(vmwrite_bitmap, 288);
CHECK_OFFSET(vm_function_control, 296);
CHECK_OFFSET(eptp_list_address, 304);
CHECK_OFFSET(pml_address, 312);
CHECK_OFFSET(encls_exiting_bitmap, 320);
CHECK_OFFSET(tsc_multiplier, 328);
CHECK_OFFSET(cr0_guest_host_mask, 344);
CHECK_OFFSET(cr4_guest_host_mask, 352);
CHECK_OFFSET(cr0_read_shadow, 360);
CHECK_OFFSET(cr4_read_shadow, 368);
CHECK_OFFSET(dead_space, 376);
CHECK_OFFSET(exit_qualification, 408);
CHECK_OFFSET(guest_linear_address, 416);
CHECK_OFFSET(guest_cr0, 424);
CHECK_OFFSET(guest_cr3, 432);
CHECK_OFFSET(guest_cr4, 440);
CHECK_OFFSET(guest_es_base, 448);
CHECK_OFFSET(guest_cs_base, 456);
CHECK_OFFSET(guest_ss_base, 464);
CHECK_OFFSET(guest_ds_base, 472);
CHECK_OFFSET(guest_fs_base, 480);
CHECK_OFFSET(guest_gs_base, 488);
CHECK_OFFSET(guest_ldtr_base, 496);
CHECK_OFFSET(guest_tr_base, 504);
CHECK_OFFSET(guest_gdtr_base, 512);
CHECK_OFFSET(guest_idtr_base, 520);
CHECK_OFFSET(guest_dr7, 528);
CHECK_OFFSET(guest_rsp, 536);
CHECK_OFFSET(guest_rip, 544);
CHECK_OFFSET(guest_rflags, 552);
CHECK_OFFSET(guest_pending_dbg_exceptions, 560);
CHECK_OFFSET(guest_sysenter_esp, 568);
CHECK_OFFSET(guest_sysenter_eip, 576);
CHECK_OFFSET(host_cr0, 584);
CHECK_OFFSET(host_cr3, 592);
CHECK_OFFSET(host_cr4, 600);
CHECK_OFFSET(host_fs_base, 608);
CHECK_OFFSET(host_gs_base, 616);
CHECK_OFFSET(host_tr_base, 624);
CHECK_OFFSET(host_gdtr_base, 632);
CHECK_OFFSET(host_idtr_base, 640);
CHECK_OFFSET(host_ia32_sysenter_esp, 648);
CHECK_OFFSET(host_ia32_sysenter_eip, 656);
CHECK_OFFSET(host_rsp, 664);
CHECK_OFFSET(host_rip, 672);
CHECK_OFFSET(host_s_cet, 680);
CHECK_OFFSET(host_ssp, 688);
CHECK_OFFSET(host_ssp_tbl, 696);
CHECK_OFFSET(guest_s_cet, 704);
CHECK_OFFSET(guest_ssp, 712);
CHECK_OFFSET(guest_ssp_tbl, 720);
CHECK_OFFSET(pin_based_vm_exec_control, 744);
CHECK_OFFSET(cpu_based_vm_exec_control, 748);
CHECK_OFFSET(exception_bitmap, 752);
CHECK_OFFSET(page_fault_error_code_mask, 756);
CHECK_OFFSET(page_fault_error_code_match, 760);
CHECK_OFFSET(cr3_target_count, 764);
CHECK_OFFSET(vm_exit_controls, 768);
CHECK_OFFSET(vm_exit_msr_store_count, 772);
CHECK_OFFSET(vm_exit_msr_load_count, 776);
CHECK_OFFSET(vm_entry_controls, 780);
CHECK_OFFSET(vm_entry_msr_load_count, 784);
CHECK_OFFSET(vm_entry_intr_info_field, 788);
CHECK_OFFSET(vm_entry_exception_error_code, 792);
CHECK_OFFSET(vm_entry_instruction_len, 796);
CHECK_OFFSET(tpr_threshold, 800);
CHECK_OFFSET(secondary_vm_exec_control, 804);
CHECK_OFFSET(vm_instruction_error, 808);
CHECK_OFFSET(vm_exit_reason, 812);
CHECK_OFFSET(vm_exit_intr_info, 816);
CHECK_OFFSET(vm_exit_intr_error_code, 820);
CHECK_OFFSET(idt_vectoring_info_field, 824);
CHECK_OFFSET(idt_vectoring_error_code, 828);
CHECK_OFFSET(vm_exit_instruction_len, 832);
CHECK_OFFSET(vmx_instruction_info, 836);
CHECK_OFFSET(guest_es_limit, 840);
CHECK_OFFSET(guest_cs_limit, 844);
CHECK_OFFSET(guest_ss_limit, 848);
CHECK_OFFSET(guest_ds_limit, 852);
CHECK_OFFSET(guest_fs_limit, 856);
CHECK_OFFSET(guest_gs_limit, 860);
CHECK_OFFSET(guest_ldtr_limit, 864);
CHECK_OFFSET(guest_tr_limit, 868);
CHECK_OFFSET(guest_gdtr_limit, 872);
CHECK_OFFSET(guest_idtr_limit, 876);
CHECK_OFFSET(guest_es_ar_bytes, 880);
CHECK_OFFSET(guest_cs_ar_bytes, 884);
CHECK_OFFSET(guest_ss_ar_bytes, 888);
CHECK_OFFSET(guest_ds_ar_bytes, 892);
CHECK_OFFSET(guest_fs_ar_bytes, 896);
CHECK_OFFSET(guest_gs_ar_bytes, 900);
CHECK_OFFSET(guest_ldtr_ar_bytes, 904);
CHECK_OFFSET(guest_tr_ar_bytes, 908);
CHECK_OFFSET(guest_interruptibility_info, 912);
CHECK_OFFSET(guest_activity_state, 916);
CHECK_OFFSET(guest_sysenter_cs, 920);
CHECK_OFFSET(host_ia32_sysenter_cs, 924);
CHECK_OFFSET(vmx_preemption_timer_value, 928);
CHECK_OFFSET(virtual_processor_id, 960);
CHECK_OFFSET(posted_intr_nv, 962);
CHECK_OFFSET(guest_es_selector, 964);
CHECK_OFFSET(guest_cs_selector, 966);
CHECK_OFFSET(guest_ss_selector, 968);
CHECK_OFFSET(guest_ds_selector, 970);
CHECK_OFFSET(guest_fs_selector, 972);
CHECK_OFFSET(guest_gs_selector, 974);
CHECK_OFFSET(guest_ldtr_selector, 976);
CHECK_OFFSET(guest_tr_selector, 978);
CHECK_OFFSET(guest_intr_status, 980);
CHECK_OFFSET(host_es_selector, 982);
CHECK_OFFSET(host_cs_selector, 984);
CHECK_OFFSET(host_ss_selector, 986);
CHECK_OFFSET(host_ds_selector, 988);
CHECK_OFFSET(host_fs_selector, 990);
CHECK_OFFSET(host_gs_selector, 992);
CHECK_OFFSET(host_tr_selector, 994);
CHECK_OFFSET(guest_pml_index, 996);
}
extern u16 vmcs12_field_offsets[] __ro_after_init;
extern unsigned int nr_vmcs12_fields __ro_after_init;
void __init nested_vmx_setup_vmcs12_fields(void);
static inline short get_vmcs12_field_offset(unsigned long field)
{
unsigned short offset;
unsigned int index;
if (field >> 15)
return -ENOENT;
index = ENC_TO_VMCS12_IDX(field);
if (index >= nr_vmcs12_fields)
return -ENOENT;
index = array_index_nospec(index, nr_vmcs12_fields);
offset = vmcs12_field_offsets[index];
if (offset == 0)
return -ENOENT;
return offset;
}
static inline u64 vmcs12_read_any(struct vmcs12 *vmcs12, unsigned long field,
u16 offset)
{
char *p = (char *)vmcs12 + offset;
switch (vmcs_field_width(field)) {
case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
return *((natural_width *)p);
case VMCS_FIELD_WIDTH_U16:
return *((u16 *)p);
case VMCS_FIELD_WIDTH_U32:
return *((u32 *)p);
case VMCS_FIELD_WIDTH_U64:
return *((u64 *)p);
default:
WARN_ON_ONCE(1);
return -1;
}
}
static inline void vmcs12_write_any(struct vmcs12 *vmcs12, unsigned long field,
u16 offset, u64 field_value)
{
char *p = (char *)vmcs12 + offset;
switch (vmcs_field_width(field)) {
case VMCS_FIELD_WIDTH_U16:
*(u16 *)p = field_value;
break;
case VMCS_FIELD_WIDTH_U32:
*(u32 *)p = field_value;
break;
case VMCS_FIELD_WIDTH_U64:
*(u64 *)p = field_value;
break;
case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
*(natural_width *)p = field_value;
break;
default:
WARN_ON_ONCE(1);
break;
}
}
#endif /* __KVM_X86_VMX_VMCS12_H */
@@ -0,0 +1,80 @@
#if !defined(SHADOW_FIELD_RO) && !defined(SHADOW_FIELD_RW)
#error Must #define at least one of SHADOW_FIELD_RO or SHADOW_FIELD_RW
#else
#ifndef SHADOW_FIELD_RO
#define SHADOW_FIELD_RO(x, y)
#endif
#ifndef SHADOW_FIELD_RW
#define SHADOW_FIELD_RW(x, y)
#endif
/*
* We do NOT shadow fields that are modified when L0
* traps and emulates any vmx instruction (e.g. VMPTRLD,
* VMXON...) executed by L1.
* For example, VM_INSTRUCTION_ERROR is read
* by L1 if a vmx instruction fails (part of the error path).
* Note the code assumes this logic. If for some reason
* we start shadowing these fields then we need to
* force a shadow sync when L0 emulates vmx instructions
* (e.g. force a sync if VM_INSTRUCTION_ERROR is modified
* by nested_vmx_failValid)
*
* When adding or removing fields here, note that shadowed
* fields must always be synced by prepare_vmcs02, not just
* prepare_vmcs02_rare.
*/
/*
* Keeping the fields ordered by size is an attempt at improving
* branch prediction in vmcs12_read_any and vmcs12_write_any.
*/
/* 16-bits */
SHADOW_FIELD_RW(GUEST_INTR_STATUS, guest_intr_status)
SHADOW_FIELD_RW(GUEST_PML_INDEX, guest_pml_index)
SHADOW_FIELD_RW(HOST_FS_SELECTOR, host_fs_selector)
SHADOW_FIELD_RW(HOST_GS_SELECTOR, host_gs_selector)
/* 32-bits */
SHADOW_FIELD_RO(VM_EXIT_REASON, vm_exit_reason)
SHADOW_FIELD_RO(VM_EXIT_INTR_INFO, vm_exit_intr_info)
SHADOW_FIELD_RO(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len)
SHADOW_FIELD_RO(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field)
SHADOW_FIELD_RO(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code)
SHADOW_FIELD_RO(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code)
SHADOW_FIELD_RO(GUEST_CS_AR_BYTES, guest_cs_ar_bytes)
SHADOW_FIELD_RO(GUEST_SS_AR_BYTES, guest_ss_ar_bytes)
SHADOW_FIELD_RW(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control)
SHADOW_FIELD_RW(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control)
SHADOW_FIELD_RW(EXCEPTION_BITMAP, exception_bitmap)
SHADOW_FIELD_RW(VM_ENTRY_EXCEPTION_ERROR_CODE, vm_entry_exception_error_code)
SHADOW_FIELD_RW(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field)
SHADOW_FIELD_RW(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len)
SHADOW_FIELD_RW(TPR_THRESHOLD, tpr_threshold)
SHADOW_FIELD_RW(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info)
SHADOW_FIELD_RW(VMX_PREEMPTION_TIMER_VALUE, vmx_preemption_timer_value)
/* Natural width */
SHADOW_FIELD_RO(EXIT_QUALIFICATION, exit_qualification)
SHADOW_FIELD_RO(GUEST_LINEAR_ADDRESS, guest_linear_address)
SHADOW_FIELD_RW(GUEST_RIP, guest_rip)
SHADOW_FIELD_RW(GUEST_RSP, guest_rsp)
SHADOW_FIELD_RW(GUEST_CR0, guest_cr0)
SHADOW_FIELD_RW(GUEST_CR3, guest_cr3)
SHADOW_FIELD_RW(GUEST_CR4, guest_cr4)
SHADOW_FIELD_RW(GUEST_RFLAGS, guest_rflags)
SHADOW_FIELD_RW(CR0_GUEST_HOST_MASK, cr0_guest_host_mask)
SHADOW_FIELD_RW(CR0_READ_SHADOW, cr0_read_shadow)
SHADOW_FIELD_RW(CR4_READ_SHADOW, cr4_read_shadow)
SHADOW_FIELD_RW(HOST_FS_BASE, host_fs_base)
SHADOW_FIELD_RW(HOST_GS_BASE, host_gs_base)
/* 64-bit */
SHADOW_FIELD_RO(GUEST_PHYSICAL_ADDRESS, guest_physical_address)
SHADOW_FIELD_RO(GUEST_PHYSICAL_ADDRESS_HIGH, guest_physical_address)
#endif
#undef SHADOW_FIELD_RO
#undef SHADOW_FIELD_RW
+274
View File
@@ -0,0 +1,274 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
#include <asm/asm.h>
#include <asm/bitsperlong.h>
#include <asm/nospec-branch.h>
#include <asm/percpu.h>
#include <asm/segment.h>
#include "kvm-asm-offsets.h"
#include "vmenter.h"
.section .noinstr.text, "ax"
/**
* __vmx_vcpu_run - Run a vCPU via a transition to VMX guest mode
* @vmx: struct vcpu_vmx *
* @flags: KVM_ENTER_VMRESUME: use VMRESUME instead of VMLAUNCH
* KVM_ENTER_SAVE_SPEC_CTRL: save guest SPEC_CTRL into vmx->spec_ctrl
* KVM_ENTER_CLEAR_CPU_BUFFERS_FOR_MMIO: vCPU can access host MMIO
*
* Returns:
* 0 on VM-Exit, 1 on VM-Fail
*/
SYM_FUNC_START(__vmx_vcpu_run)
push %_ASM_BP
mov %_ASM_SP, %_ASM_BP
#ifdef CONFIG_X86_64
push %r15
push %r14
push %r13
push %r12
#else
push %edi
push %esi
#endif
push %_ASM_BX
/* Save @vmx for SPEC_CTRL handling */
push %_ASM_ARG1
/* Save @flags (used for VMLAUNCH vs. VMRESUME and mitigations). */
push %_ASM_ARG2
lea (%_ASM_SP), %_ASM_ARG2
call vmx_update_host_rsp
/* Reload @vmx, _ASM_ARG1 may be modified by vmx_update_host_rsp(). */
mov WORD_SIZE(%_ASM_SP), %_ASM_DI
/*
* Unlike AMD there's no V_SPEC_CTRL here, so do not leave the body
* out of line. Clobbers RAX, RCX, RDX, RSI.
*/
ALTERNATIVE "jmp .Lspec_ctrl_guest_done", "", X86_FEATURE_MSR_SPEC_CTRL
RESTORE_GUEST_SPEC_CTRL_BODY VMX_spec_ctrl(%_ASM_DI), .Lspec_ctrl_guest_done
.Lspec_ctrl_guest_done:
/*
* Since vmentry is serializing on affected CPUs, there's no need for
* an LFENCE to stop speculation from skipping the wrmsr.
*/
/*
* Load guest registers. Don't clobber flags. Intentionally omit
* %_ASM_SP as it's context switched by hardware
*/
LOAD_REGS %_ASM_DI, VMX_vcpu_arch_regs, \
%_ASM_AX, %_ASM_CX, %_ASM_DX, %_ASM_BX, %_ASM_BP, %_ASM_SI
#ifdef CONFIG_X86_64
LOAD_REGS %_ASM_DI, VMX_vcpu_arch_regs, \
%r8, %r9, %r10, %r11, %r12, %r13, %r14, %r15
#endif
/* Load guest RDI. This kills the @vmx pointer! */
LOAD_REGS %_ASM_DI, VMX_vcpu_arch_regs, %_ASM_DI
/*
* Note, ALTERNATIVE_2 works in reverse order. If CLEAR_CPU_BUF_VM is
* enabled, do VERW unconditionally. If CPU_BUF_VM_MMIO is enabled,
* check @flags to see if the vCPU has access to host MMIO, and if so,
* do VERW. Else, do nothing (no mitigations needed/enabled).
*/
ALTERNATIVE_2 "", \
__stringify(testl $KVM_ENTER_CLEAR_CPU_BUFFERS_FOR_MMIO, (%_ASM_SP); \
jz .Lskip_mmio_verw; \
VERW; \
.Lskip_mmio_verw:), \
X86_FEATURE_CLEAR_CPU_BUF_VM_MMIO, \
__stringify(VERW), X86_FEATURE_CLEAR_CPU_BUF_VM
/* Check @flags to see if VMLAUNCH or VMRESUME is needed. */
testl $KVM_ENTER_VMRESUME, (%_ASM_SP)
jz .Lvmlaunch
/*
* After a successful VMRESUME/VMLAUNCH, control flow "magically"
* resumes below at 'vmx_vmexit' due to the VMCS HOST_RIP setting.
* So this isn't a typical function and objtool needs to be told to
* save the unwind state here and restore it below.
*/
UNWIND_HINT_SAVE
/*
* If VMRESUME/VMLAUNCH and corresponding vmexit succeed, execution resumes at
* the 'vmx_vmexit' label below.
*/
.Lvmresume:
vmresume
jmp .Lvmfail
.Lvmlaunch:
vmlaunch
jmp .Lvmfail
_ASM_EXTABLE(.Lvmresume, .Lfixup)
_ASM_EXTABLE(.Lvmlaunch, .Lfixup)
SYM_INNER_LABEL_ALIGN(vmx_vmexit, SYM_L_GLOBAL)
/* Restore unwind state from before the VMRESUME/VMLAUNCH. */
UNWIND_HINT_RESTORE
ENDBR
/* Temporarily save guest's RDI. */
push %_ASM_DI
/* Reload @vmx to RDI. */
mov 2*WORD_SIZE(%_ASM_SP), %_ASM_DI
/*
* Save all guest registers, including RDI from the stack. Intentionally
* omit %_ASM_SP as it's context switched by hardware
*/
STORE_REGS %_ASM_DI, VMX_vcpu_arch_regs, \
%_ASM_AX, %_ASM_CX, %_ASM_DX, %_ASM_BX, %_ASM_BP, %_ASM_SI
POP_REGS %_ASM_DI, VMX_vcpu_arch_regs, %_ASM_DI
#ifdef CONFIG_X86_64
STORE_REGS %_ASM_DI, VMX_vcpu_arch_regs, \
%r8, %r9, %r10, %r11, %r12, %r13, %r14, %r15
#endif
/* Clear return value to indicate VM-Exit (as opposed to VM-Fail). */
xor %ebx, %ebx
.Lclear_regs:
/*
* Clear all general purpose registers except RSP and RBX to prevent
* speculative use of the guest's values, even those that are reloaded
* via the stack. In theory, an L1 cache miss when restoring registers
* could lead to speculative execution with the guest's values.
* Zeroing XORs are dirt cheap, i.e. the extra paranoia is essentially
* free. RSP and RBX are exempt as RSP is restored by hardware during
* VM-Exit and RBX is explicitly loaded with 0 or 1 to hold the return
* value.
*/
CLEAR_REGS %eax, %ecx, %edx, %ebp, %esi, %edi
#ifdef CONFIG_X86_64
CLEAR_REGS %r8d, %r9d, %r10d, %r11d, %r12d, %r13d, %r14d, %r15d
#endif
/*
* IMPORTANT: RSB filling and SPEC_CTRL handling must be done before
* the first unbalanced RET after vmexit!
*
* For retpoline or IBRS, RSB filling is needed to prevent poisoned RSB
* entries and (in some cases) RSB underflow.
*
* eIBRS has its own protection against poisoned RSB, so it doesn't
* need the RSB filling sequence. But it does need to be enabled, and a
* single call to retire, before the first unbalanced RET.
*/
FILL_RETURN_BUFFER %_ASM_CX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT,\
X86_FEATURE_RSB_VMEXIT_LITE
/* Clobbers RAX, RCX, RDX, RSI. */
ALTERNATIVE "jmp .Lspec_ctrl_host_done", "", X86_FEATURE_MSR_SPEC_CTRL
mov WORD_SIZE(%_ASM_SP), %_ASM_DI
RESTORE_HOST_SPEC_CTRL_BODY VMX_spec_ctrl(%_ASM_DI), (%_ASM_SP), .Lspec_ctrl_host_done
.Lspec_ctrl_host_done:
/*
* Halt speculation past a conditional wrmsr. Intel's eIBRS
* guarantees that the guest cannot control the RSB "once IBRS is
* set", but in the eIBRS case speculative execution past the 'je'
* can go all the way to the RET below while MSR_IA32_SPEC_CTRL
* still holds the guest value.
*/
ALTERNATIVE_2 "", "lfence", X86_FEATURE_MSR_SPEC_CTRL, \
"", X86_FEATURE_KERNEL_IBRS
CLEAR_BRANCH_HISTORY_VMEXIT
/* Put return value in AX */
mov %_ASM_BX, %_ASM_AX
/* Pop our saved arguments from the stack */
pop %_ASM_BX
pop %_ASM_BX
/* ... and then the callee-save registers */
pop %_ASM_BX
#ifdef CONFIG_X86_64
pop %r12
pop %r13
pop %r14
pop %r15
#else
pop %esi
pop %edi
#endif
pop %_ASM_BP
RET
.Lfixup:
cmpb $0, _ASM_RIP(virt_rebooting)
jne .Lvmfail
ud2
.Lvmfail:
/* VM-Fail: set return value to 1 */
mov $1, %_ASM_BX
jmp .Lclear_regs
SYM_FUNC_END(__vmx_vcpu_run)
#ifndef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
/**
* vmread_error_trampoline - Trampoline from inline asm to vmread_error()
* @field: VMCS field encoding that failed
* @fault: %true if the VMREAD faulted, %false if it failed
*
* Save and restore volatile registers across a call to vmread_error(). Note,
* all parameters are passed on the stack.
*/
SYM_FUNC_START(vmread_error_trampoline)
push %_ASM_BP
mov %_ASM_SP, %_ASM_BP
push %_ASM_AX
push %_ASM_CX
push %_ASM_DX
#ifdef CONFIG_X86_64
push %rdi
push %rsi
push %r8
push %r9
push %r10
push %r11
#endif
/* Load @field and @fault to arg1 and arg2 respectively. */
mov 3*WORD_SIZE(%_ASM_BP), %_ASM_ARG2
mov 2*WORD_SIZE(%_ASM_BP), %_ASM_ARG1
call vmread_error_trampoline2
/* Zero out @fault, which will be popped into the result register. */
_ASM_MOV $0, 3*WORD_SIZE(%_ASM_BP)
#ifdef CONFIG_X86_64
pop %r11
pop %r10
pop %r9
pop %r8
pop %rsi
pop %rdi
#endif
pop %_ASM_DX
pop %_ASM_CX
pop %_ASM_AX
pop %_ASM_BP
RET
SYM_FUNC_END(vmread_error_trampoline)
#endif
File diff suppressed because it is too large Load Diff
+735
View File
@@ -0,0 +1,735 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_H
#define __KVM_X86_VMX_H
#include <linux/kvm_host.h>
#include <asm/kvm.h>
#include <asm/intel_pt.h>
#include <asm/perf_event.h>
#include <asm/posted_intr.h>
#include "capabilities.h"
#include "../regs.h"
#include "pmu_intel.h"
#include "vmcs.h"
#include "vmx_ops.h"
#include "../cpuid.h"
#include "../mmu.h"
#include "common.h"
#ifdef CONFIG_X86_64
#define MAX_NR_USER_RETURN_MSRS 7
#else
#define MAX_NR_USER_RETURN_MSRS 4
#endif
#define MAX_NR_LOADSTORE_MSRS 8
struct vmx_msrs {
unsigned int nr;
struct vmx_msr_entry val[MAX_NR_LOADSTORE_MSRS];
};
struct vmx_uret_msr {
bool load_into_hardware;
u64 data;
u64 mask;
};
enum segment_cache_field {
SEG_FIELD_SEL = 0,
SEG_FIELD_BASE = 1,
SEG_FIELD_LIMIT = 2,
SEG_FIELD_AR = 3,
SEG_FIELD_NR = 4
};
#define RTIT_ADDR_RANGE 4
struct pt_ctx {
u64 ctl;
u64 status;
u64 output_base;
u64 output_mask;
u64 cr3_match;
u64 addr_a[RTIT_ADDR_RANGE];
u64 addr_b[RTIT_ADDR_RANGE];
};
struct pt_desc {
u64 ctl_bitmask;
u32 num_address_ranges;
u32 caps[PT_CPUID_REGS_NUM * PT_CPUID_LEAVES];
struct pt_ctx host;
struct pt_ctx guest;
};
/*
* The nested_vmx structure is part of vcpu_vmx, and holds information we need
* for correct emulation of VMX (i.e., nested VMX) on this vcpu.
*/
struct nested_vmx {
/* Has the level1 guest done vmxon? */
bool vmxon;
gpa_t vmxon_ptr;
bool pml_full;
/* The guest-physical address of the current VMCS L1 keeps for L2 */
gpa_t current_vmptr;
/*
* Cache of the guest's VMCS, existing outside of guest memory.
* Loaded from guest memory during VMPTRLD. Flushed to guest
* memory during VMCLEAR and VMPTRLD.
*/
struct vmcs12 *cached_vmcs12;
/*
* Cache of the guest's shadow VMCS, existing outside of guest
* memory. Loaded from guest memory during VM entry. Flushed
* to guest memory during VM exit.
*/
struct vmcs12 *cached_shadow_vmcs12;
/*
* GPA to HVA cache for accessing vmcs12->vmcs_link_pointer
*/
struct gfn_to_hva_cache shadow_vmcs12_cache;
/*
* GPA to HVA cache for VMCS12
*/
struct gfn_to_hva_cache vmcs12_cache;
/*
* Indicates if the shadow vmcs or enlightened vmcs must be updated
* with the data held by struct vmcs12.
*/
bool need_vmcs12_to_shadow_sync;
bool dirty_vmcs12;
/*
* Indicates whether MSR bitmap for L2 needs to be rebuilt due to
* changes in MSR bitmap for L1 or switching to a different L2. Note,
* this flag can only be used reliably in conjunction with a paravirt L1
* which informs L0 whether any changes to MSR bitmap for L2 were done
* on its side.
*/
bool force_msr_bitmap_recalc;
/*
* Indicates lazily loaded guest state has not yet been decached from
* vmcs02.
*/
bool need_sync_vmcs02_to_vmcs12_rare;
/*
* vmcs02 has been initialized, i.e. state that is constant for
* vmcs02 has been written to the backing VMCS. Initialization
* is delayed until L1 actually attempts to run a nested VM.
*/
bool vmcs02_initialized;
/*
* Enlightened VMCS has been enabled. It does not mean that L1 has to
* use it. However, VMX features available to L1 will be limited based
* on what the enlightened VMCS supports.
*/
bool enlightened_vmcs_enabled;
/* Pending MTF VM-exit into L1. */
bool mtf_pending;
struct loaded_vmcs vmcs02;
/*
* Guest pages referred to in the vmcs02 with host-physical
* pointers, so we must keep them pinned while L2 runs.
*/
struct kvm_host_map apic_access_page_map;
struct kvm_host_map virtual_apic_map;
struct kvm_host_map pi_desc_map;
struct pi_desc *pi_desc;
bool pi_pending;
u16 posted_intr_nv;
struct hrtimer preemption_timer;
u64 preemption_timer_deadline;
bool has_preemption_timer_deadline;
bool preemption_timer_expired;
/*
* Used to restore L1's CR3 if hardware detects a VM-Fail Consistency
* Check that KVM does not, in which case KVM needs to unwind CR3 back
* to its pre-VM-Enter state, NOT to vmcs01.HOST_CR3.
*/
unsigned long pre_vmenter_cr3;
/*
* Used to snapshot MSRs that are conditionally loaded on VM-Enter in
* order to propagate the guest's pre-VM-Enter value into vmcs02. For
* emulation of VMLAUNCH/VMRESUME, the snapshot will be of L1's value.
* For KVM_SET_NESTED_STATE, the snapshot is of L2's value, _if_
* userspace restores MSRs before nested state. If userspace restores
* MSRs after nested state, the snapshot holds garbage, but KVM can't
* detect that, and the garbage value in vmcs02 will be overwritten by
* MSR restoration in any case.
*/
u64 pre_vmenter_debugctl;
u64 pre_vmenter_bndcfgs;
u64 pre_vmenter_s_cet;
u64 pre_vmenter_ssp;
u64 pre_vmenter_ssp_tbl;
u16 vpid02;
u16 last_vpid;
int tsc_autostore_slot;
struct nested_vmx_msrs msrs;
/* SMM related state */
struct {
/* in VMX operation on SMM entry? */
bool vmxon;
/* in guest mode on SMM entry? */
bool guest_mode;
} smm;
#ifdef CONFIG_KVM_HYPERV
gpa_t hv_evmcs_vmptr;
struct kvm_host_map hv_evmcs_map;
struct hv_enlightened_vmcs *hv_evmcs;
#endif
};
struct vcpu_vmx {
struct kvm_vcpu vcpu;
struct vcpu_vt vt;
u8 fail;
u8 x2apic_msr_bitmap_mode;
u32 idt_vectoring_info;
ulong rflags;
/*
* User return MSRs are always emulated when enabled in the guest, but
* only loaded into hardware when necessary, e.g. SYSCALL #UDs outside
* of 64-bit mode or if EFER.SCE=1, thus the SYSCALL MSRs don't need to
* be loaded into hardware if those conditions aren't met.
*/
struct vmx_uret_msr guest_uret_msrs[MAX_NR_USER_RETURN_MSRS];
bool guest_uret_msrs_loaded;
#ifdef CONFIG_X86_64
u64 msr_guest_kernel_gs_base;
#endif
u64 spec_ctrl;
u32 msr_ia32_umwait_control;
/*
* loaded_vmcs points to the VMCS currently used in this vcpu. For a
* non-nested (L1) guest, it always points to vmcs01. For a nested
* guest (L2), it points to a different VMCS.
*/
struct loaded_vmcs vmcs01;
struct loaded_vmcs *loaded_vmcs;
struct msr_autoload {
struct vmx_msrs guest;
struct vmx_msrs host;
} msr_autoload;
struct vmx_msrs msr_autostore;
struct {
int vm86_active;
ulong save_rflags;
struct kvm_segment segs[8];
} rmode;
struct {
u32 bitmask; /* 4 bits per segment (1 bit per field) */
struct kvm_save_segment {
u16 selector;
unsigned long base;
u32 limit;
u32 ar;
} seg[8];
} segment_cache;
int vpid;
/* Support for a guest hypervisor (nested VMX) */
struct nested_vmx nested;
/* Dynamic PLE window. */
unsigned int ple_window;
bool ple_window_dirty;
/* Support for PML */
#define PML_LOG_NR_ENTRIES 512
/* PML is written backwards: this is the first entry written by the CPU */
#define PML_HEAD_INDEX (PML_LOG_NR_ENTRIES-1)
struct page *pml_pg;
/* apic deadline value in host tsc */
u64 hv_deadline_tsc;
/*
* Only bits masked by msr_ia32_feature_control_valid_bits can be set in
* msr_ia32_feature_control. FEAT_CTL_LOCKED is always included
* in msr_ia32_feature_control_valid_bits.
*/
u64 msr_ia32_feature_control;
u64 msr_ia32_feature_control_valid_bits;
/* SGX Launch Control public key hash */
u64 msr_ia32_sgxlepubkeyhash[4];
u64 msr_ia32_mcu_opt_ctrl;
bool disable_fb_clear;
struct pt_desc pt_desc;
struct lbr_desc lbr_desc;
/* ve_info must be page aligned. */
struct vmx_ve_information *ve_info;
};
struct kvm_vmx {
struct kvm kvm;
unsigned int tss_addr;
bool ept_identity_pagetable_done;
gpa_t ept_identity_map_addr;
/* Posted Interrupt Descriptor (PID) table for IPI virtualization */
u64 *pid_table;
};
static __always_inline struct vcpu_vt *to_vt(struct kvm_vcpu *vcpu)
{
return &(container_of(vcpu, struct vcpu_vmx, vcpu)->vt);
}
static __always_inline struct kvm_vcpu *vt_to_vcpu(struct vcpu_vt *vt)
{
return &(container_of(vt, struct vcpu_vmx, vt)->vcpu);
}
static __always_inline union vmx_exit_reason vmx_get_exit_reason(struct kvm_vcpu *vcpu)
{
return to_vt(vcpu)->exit_reason;
}
static __always_inline unsigned long vmx_get_exit_qual(struct kvm_vcpu *vcpu)
{
struct vcpu_vt *vt = to_vt(vcpu);
if (!kvm_register_test_and_mark_available(vcpu, VCPU_REG_EXIT_INFO_1) &&
!WARN_ON_ONCE(is_td_vcpu(vcpu)))
vt->exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
return vt->exit_qualification;
}
static __always_inline u32 vmx_get_intr_info(struct kvm_vcpu *vcpu)
{
struct vcpu_vt *vt = to_vt(vcpu);
if (!kvm_register_test_and_mark_available(vcpu, VCPU_REG_EXIT_INFO_2) &&
!WARN_ON_ONCE(is_td_vcpu(vcpu)))
vt->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
return vt->exit_intr_info;
}
void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu);
int allocate_vpid(void);
void free_vpid(int vpid);
void vmx_set_constant_host_state(struct vcpu_vmx *vmx);
void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu);
void vmx_set_host_fs_gs(struct vmcs_host_state *host, u16 fs_sel, u16 gs_sel,
unsigned long fs_base, unsigned long gs_base);
int vmx_get_cpl(struct kvm_vcpu *vcpu);
int vmx_get_cpl_no_cache(struct kvm_vcpu *vcpu);
bool vmx_emulation_required(struct kvm_vcpu *vcpu);
unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu);
void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu);
void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask);
int vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer);
void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
void set_cr4_guest_host_mask(struct vcpu_vmx *vmx);
void ept_save_pdptrs(struct kvm_vcpu *vcpu);
void vmx_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
void __vmx_set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
bool vmx_guest_inject_ac(struct kvm_vcpu *vcpu);
void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu);
bool vmx_nmi_blocked(struct kvm_vcpu *vcpu);
bool __vmx_interrupt_blocked(struct kvm_vcpu *vcpu);
bool vmx_interrupt_blocked(struct kvm_vcpu *vcpu);
bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu);
void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked);
void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu);
struct vmx_uret_msr *vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr);
void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu);
void vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp);
unsigned int __vmx_vcpu_enter_flags(struct vcpu_vmx *vmx);
bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned int flags);
void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu);
void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type, bool set);
static inline void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu,
u32 msr, int type)
{
vmx_set_intercept_for_msr(vcpu, msr, type, false);
}
static inline void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu,
u32 msr, int type)
{
vmx_set_intercept_for_msr(vcpu, msr, type, true);
}
u64 vmx_get_l2_tsc_offset(struct kvm_vcpu *vcpu);
u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu);
gva_t vmx_get_untagged_addr(struct kvm_vcpu *vcpu, gva_t gva, unsigned int flags);
void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu);
u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiated);
bool vmx_is_valid_debugctl(struct kvm_vcpu *vcpu, u64 data, bool host_initiated);
#define VMX_HOST_OWNED_DEBUGCTL_BITS (DEBUGCTLMSR_FREEZE_IN_SMM)
static inline void vmx_guest_debugctl_write(struct kvm_vcpu *vcpu, u64 val)
{
WARN_ON_ONCE(val & VMX_HOST_OWNED_DEBUGCTL_BITS);
val |= vcpu->arch.host_debugctl & VMX_HOST_OWNED_DEBUGCTL_BITS;
vmcs_write64(GUEST_IA32_DEBUGCTL, val);
}
static inline u64 vmx_guest_debugctl_read(void)
{
return vmcs_read64(GUEST_IA32_DEBUGCTL) & ~VMX_HOST_OWNED_DEBUGCTL_BITS;
}
static inline void vmx_reload_guest_debugctl(struct kvm_vcpu *vcpu)
{
u64 val = vmcs_read64(GUEST_IA32_DEBUGCTL);
if (!((val ^ vcpu->arch.host_debugctl) & VMX_HOST_OWNED_DEBUGCTL_BITS))
return;
vmx_guest_debugctl_write(vcpu, val & ~VMX_HOST_OWNED_DEBUGCTL_BITS);
}
/*
* Note, early Intel manuals have the write-low and read-high bitmap offsets
* the wrong way round. The bitmaps control MSRs 0x00000000-0x00001fff and
* 0xc0000000-0xc0001fff. The former (low) uses bytes 0-0x3ff for reads and
* 0x800-0xbff for writes. The latter (high) uses 0x400-0x7ff for reads and
* 0xc00-0xfff for writes. MSRs not covered by either of the ranges always
* VM-Exit.
*/
#define __BUILD_VMX_MSR_BITMAP_HELPER(rtype, action, bitop, access, base) \
static inline rtype vmx_##action##_msr_bitmap_##access(unsigned long *bitmap, \
u32 msr) \
{ \
int f = sizeof(unsigned long); \
\
if (msr <= 0x1fff) \
return bitop##_bit(msr, bitmap + base / f); \
else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) \
return bitop##_bit(msr & 0x1fff, bitmap + (base + 0x400) / f); \
return (rtype)true; \
}
#define BUILD_VMX_MSR_BITMAP_HELPERS(ret_type, action, bitop) \
__BUILD_VMX_MSR_BITMAP_HELPER(ret_type, action, bitop, read, 0x0) \
__BUILD_VMX_MSR_BITMAP_HELPER(ret_type, action, bitop, write, 0x800)
BUILD_VMX_MSR_BITMAP_HELPERS(bool, test, test)
BUILD_VMX_MSR_BITMAP_HELPERS(void, clear, __clear)
BUILD_VMX_MSR_BITMAP_HELPERS(void, set, __set)
static inline u8 vmx_get_rvi(void)
{
return vmcs_read16(GUEST_INTR_STATUS) & 0xff;
}
#define __KVM_REQUIRED_VMX_VM_ENTRY_CONTROLS \
(VM_ENTRY_LOAD_DEBUG_CONTROLS)
#ifdef CONFIG_X86_64
#define KVM_REQUIRED_VMX_VM_ENTRY_CONTROLS \
(__KVM_REQUIRED_VMX_VM_ENTRY_CONTROLS | \
VM_ENTRY_IA32E_MODE)
#else
#define KVM_REQUIRED_VMX_VM_ENTRY_CONTROLS \
__KVM_REQUIRED_VMX_VM_ENTRY_CONTROLS
#endif
#define KVM_OPTIONAL_VMX_VM_ENTRY_CONTROLS \
(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 | \
VM_ENTRY_LOAD_CET_STATE)
#define __KVM_REQUIRED_VMX_VM_EXIT_CONTROLS \
(VM_EXIT_SAVE_DEBUG_CONTROLS | \
VM_EXIT_ACK_INTR_ON_EXIT)
#ifdef CONFIG_X86_64
#define KVM_REQUIRED_VMX_VM_EXIT_CONTROLS \
(__KVM_REQUIRED_VMX_VM_EXIT_CONTROLS | \
VM_EXIT_HOST_ADDR_SPACE_SIZE)
#else
#define KVM_REQUIRED_VMX_VM_EXIT_CONTROLS \
__KVM_REQUIRED_VMX_VM_EXIT_CONTROLS
#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 | \
VM_EXIT_CLEAR_IA32_RTIT_CTL | \
VM_EXIT_LOAD_CET_STATE | \
VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL)
#define KVM_REQUIRED_VMX_PIN_BASED_VM_EXEC_CONTROL \
(PIN_BASED_EXT_INTR_MASK | \
PIN_BASED_NMI_EXITING)
#define KVM_OPTIONAL_VMX_PIN_BASED_VM_EXEC_CONTROL \
(PIN_BASED_VIRTUAL_NMIS | \
PIN_BASED_POSTED_INTR | \
PIN_BASED_VMX_PREEMPTION_TIMER)
#define __KVM_REQUIRED_VMX_CPU_BASED_VM_EXEC_CONTROL \
(CPU_BASED_HLT_EXITING | \
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)
#ifdef CONFIG_X86_64
#define KVM_REQUIRED_VMX_CPU_BASED_VM_EXEC_CONTROL \
(__KVM_REQUIRED_VMX_CPU_BASED_VM_EXEC_CONTROL | \
CPU_BASED_CR8_LOAD_EXITING | \
CPU_BASED_CR8_STORE_EXITING)
#else
#define KVM_REQUIRED_VMX_CPU_BASED_VM_EXEC_CONTROL \
__KVM_REQUIRED_VMX_CPU_BASED_VM_EXEC_CONTROL
#endif
#define KVM_OPTIONAL_VMX_CPU_BASED_VM_EXEC_CONTROL \
(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)
#define KVM_REQUIRED_VMX_SECONDARY_VM_EXEC_CONTROL 0
#define KVM_OPTIONAL_VMX_SECONDARY_VM_EXEC_CONTROL \
(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_ENABLE_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_MODE_BASED_EPT_EXEC | \
SECONDARY_EXEC_ENCLS_EXITING | \
SECONDARY_EXEC_EPT_VIOLATION_VE)
#define KVM_REQUIRED_VMX_TERTIARY_VM_EXEC_CONTROL 0
#define KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL \
(TERTIARY_EXEC_IPI_VIRT)
#define BUILD_CONTROLS_SHADOW(lname, uname, bits) \
static inline void lname##_controls_set(struct vcpu_vmx *vmx, u##bits val) \
{ \
if (vmx->loaded_vmcs->controls_shadow.lname != val) { \
vmcs_write##bits(uname, val); \
vmx->loaded_vmcs->controls_shadow.lname = val; \
} \
} \
static inline u##bits __##lname##_controls_get(struct loaded_vmcs *vmcs) \
{ \
return vmcs->controls_shadow.lname; \
} \
static inline u##bits lname##_controls_get(struct vcpu_vmx *vmx) \
{ \
return __##lname##_controls_get(vmx->loaded_vmcs); \
} \
static __always_inline void lname##_controls_setbit(struct vcpu_vmx *vmx, u##bits val) \
{ \
BUILD_BUG_ON(!(val & (KVM_REQUIRED_VMX_##uname | KVM_OPTIONAL_VMX_##uname))); \
lname##_controls_set(vmx, lname##_controls_get(vmx) | val); \
} \
static __always_inline void lname##_controls_clearbit(struct vcpu_vmx *vmx, u##bits val) \
{ \
BUILD_BUG_ON(!(val & (KVM_REQUIRED_VMX_##uname | KVM_OPTIONAL_VMX_##uname))); \
lname##_controls_set(vmx, lname##_controls_get(vmx) & ~val); \
} \
static __always_inline void lname##_controls_changebit(struct vcpu_vmx *vmx, u##bits val, \
bool set) \
{ \
if (set) \
lname##_controls_setbit(vmx, val); \
else \
lname##_controls_clearbit(vmx, val); \
}
BUILD_CONTROLS_SHADOW(vm_entry, VM_ENTRY_CONTROLS, 32)
BUILD_CONTROLS_SHADOW(vm_exit, VM_EXIT_CONTROLS, 32)
BUILD_CONTROLS_SHADOW(pin, PIN_BASED_VM_EXEC_CONTROL, 32)
BUILD_CONTROLS_SHADOW(exec, CPU_BASED_VM_EXEC_CONTROL, 32)
BUILD_CONTROLS_SHADOW(secondary_exec, SECONDARY_VM_EXEC_CONTROL, 32)
BUILD_CONTROLS_SHADOW(tertiary_exec, TERTIARY_VM_EXEC_CONTROL, 64)
/*
* VMX_REGS_LAZY_LOAD_SET - The set of registers that will be updated in the
* cache on demand. Other registers not listed here are synced to
* the cache immediately after VM-Exit.
*/
#define VMX_REGS_LAZY_LOAD_SET (BIT(VCPU_REGS_RSP) | \
BIT(VCPU_REG_RIP) | \
BIT(VCPU_REG_RFLAGS) | \
BIT(VCPU_REG_PDPTR) | \
BIT(VCPU_REG_SEGMENTS) | \
BIT(VCPU_REG_CR0) | \
BIT(VCPU_REG_CR3) | \
BIT(VCPU_REG_CR4) | \
BIT(VCPU_REG_EXIT_INFO_1) | \
BIT(VCPU_REG_EXIT_INFO_2))
static inline unsigned long vmx_l1_guest_owned_cr0_bits(void)
{
unsigned long bits = KVM_POSSIBLE_CR0_GUEST_BITS;
/*
* CR0.WP needs to be intercepted when KVM is shadowing legacy paging
* in order to construct shadow PTEs with the correct protections.
* Note! CR0.WP technically can be passed through to the guest if
* paging is disabled, but checking CR0.PG would generate a cyclical
* dependency of sorts due to forcing the caller to ensure CR0 holds
* the correct value prior to determining which CR0 bits can be owned
* by L1. Keep it simple and limit the optimization to EPT.
*/
if (!enable_ept)
bits &= ~X86_CR0_WP;
return bits;
}
static __always_inline struct kvm_vmx *to_kvm_vmx(struct kvm *kvm)
{
return container_of(kvm, struct kvm_vmx, kvm);
}
static __always_inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
{
return container_of(vcpu, struct vcpu_vmx, vcpu);
}
void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu);
int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu);
void vmx_passthrough_lbr_msrs(struct kvm_vcpu *vcpu);
struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags);
void free_vmcs(struct vmcs *vmcs);
int alloc_loaded_vmcs(struct loaded_vmcs *loaded_vmcs);
void free_loaded_vmcs(struct loaded_vmcs *loaded_vmcs);
static inline struct vmcs *alloc_vmcs(bool shadow)
{
return alloc_vmcs_cpu(shadow, raw_smp_processor_id(),
GFP_KERNEL_ACCOUNT);
}
static inline bool vmx_has_waitpkg(struct vcpu_vmx *vmx)
{
return secondary_exec_controls_get(vmx) &
SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
}
static inline bool vmx_need_pf_intercept(struct kvm_vcpu *vcpu)
{
if (!enable_ept)
return true;
return allow_smaller_maxphyaddr &&
cpuid_maxphyaddr(vcpu) < kvm_host.maxphyaddr;
}
static inline bool is_unrestricted_guest(struct kvm_vcpu *vcpu)
{
return enable_unrestricted_guest && (!is_guest_mode(vcpu) ||
(secondary_exec_controls_get(to_vmx(vcpu)) &
SECONDARY_EXEC_UNRESTRICTED_GUEST));
}
bool __vmx_guest_state_valid(struct kvm_vcpu *vcpu);
static inline bool vmx_guest_state_valid(struct kvm_vcpu *vcpu)
{
return is_unrestricted_guest(vcpu) || __vmx_guest_state_valid(vcpu);
}
void dump_vmcs(struct kvm_vcpu *vcpu);
static inline int vmx_get_instr_info_reg(u32 vmx_instr_info)
{
return (vmx_instr_info >> 3) & 0xf;
}
static inline int vmx_get_instr_info_reg2(u32 vmx_instr_info)
{
return (vmx_instr_info >> 28) & 0xf;
}
static inline bool vmx_can_use_ipiv(struct kvm_vcpu *vcpu)
{
return lapic_in_kernel(vcpu) && enable_ipiv;
}
static inline void vmx_segment_cache_clear(struct vcpu_vmx *vmx)
{
vmx->segment_cache.bitmask = 0;
}
int vmx_init(void);
void vmx_exit(void);
#endif /* __KVM_X86_VMX_H */
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "capabilities.h"
#include "vmx_onhyperv.h"
DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
/*
* KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption
* is: in case a feature has corresponding fields in eVMCS described and it was
* exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a
* feature which has no corresponding eVMCS field, this likely means that KVM
* needs to be updated.
*/
#define evmcs_check_vmcs_conf(field, ctrl) \
do { \
typeof(vmcs_conf->field) unsupported; \
\
unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \
if (unsupported) { \
pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\
(u64)unsupported); \
vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \
} \
} \
while (0)
void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
{
evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL);
evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL);
evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC);
evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC);
evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL);
evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL);
}
+133
View File
@@ -0,0 +1,133 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __ARCH_X86_KVM_VMX_ONHYPERV_H__
#define __ARCH_X86_KVM_VMX_ONHYPERV_H__
#include <hyperv/hvhdk.h>
#include <asm/mshyperv.h>
#include <linux/jump_label.h>
#include "capabilities.h"
#include "hyperv_evmcs.h"
#include "vmcs12.h"
#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
#if IS_ENABLED(CONFIG_HYPERV)
DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
static __always_inline bool kvm_is_using_evmcs(void)
{
return static_branch_unlikely(&__kvm_is_using_evmcs);
}
static __always_inline int get_evmcs_offset(unsigned long field,
u16 *clean_field)
{
int offset = evmcs_field_offset(field, clean_field);
WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field);
return offset;
}
static __always_inline void evmcs_write64(unsigned long field, u64 value)
{
u16 clean_field;
int offset = get_evmcs_offset(field, &clean_field);
if (offset < 0)
return;
*(u64 *)((char *)current_evmcs + offset) = value;
current_evmcs->hv_clean_fields &= ~clean_field;
}
static __always_inline void evmcs_write32(unsigned long field, u32 value)
{
u16 clean_field;
int offset = get_evmcs_offset(field, &clean_field);
if (offset < 0)
return;
*(u32 *)((char *)current_evmcs + offset) = value;
current_evmcs->hv_clean_fields &= ~clean_field;
}
static __always_inline void evmcs_write16(unsigned long field, u16 value)
{
u16 clean_field;
int offset = get_evmcs_offset(field, &clean_field);
if (offset < 0)
return;
*(u16 *)((char *)current_evmcs + offset) = value;
current_evmcs->hv_clean_fields &= ~clean_field;
}
static __always_inline u64 evmcs_read64(unsigned long field)
{
int offset = get_evmcs_offset(field, NULL);
if (offset < 0)
return 0;
return *(u64 *)((char *)current_evmcs + offset);
}
static __always_inline u32 evmcs_read32(unsigned long field)
{
int offset = get_evmcs_offset(field, NULL);
if (offset < 0)
return 0;
return *(u32 *)((char *)current_evmcs + offset);
}
static __always_inline u16 evmcs_read16(unsigned long field)
{
int offset = get_evmcs_offset(field, NULL);
if (offset < 0)
return 0;
return *(u16 *)((char *)current_evmcs + offset);
}
static inline void evmcs_load(u64 phys_addr)
{
struct hv_vp_assist_page *vp_ap =
hv_get_vp_assist_page(smp_processor_id());
/*
* When enabling eVMCS, KVM verifies that every CPU has a valid hv_vp_assist_page()
* and aborts enabling the feature otherwise. CPU onlining path is also checked in
* vmx_hardware_enable().
*/
if (KVM_BUG_ON(!vp_ap, kvm_get_running_vcpu()->kvm))
return;
if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall)
vp_ap->nested_control.features.directhypercall = 1;
vp_ap->current_nested_vmcs = phys_addr;
vp_ap->enlighten_vmentry = 1;
}
void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
#else /* !IS_ENABLED(CONFIG_HYPERV) */
static __always_inline bool kvm_is_using_evmcs(void) { return false; }
static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
static __always_inline void evmcs_write32(unsigned long field, u32 value) {}
static __always_inline void evmcs_write16(unsigned long field, u16 value) {}
static __always_inline u64 evmcs_read64(unsigned long field) { return 0; }
static __always_inline u32 evmcs_read32(unsigned long field) { return 0; }
static __always_inline u16 evmcs_read16(unsigned long field) { return 0; }
static inline void evmcs_load(u64 phys_addr) {}
#endif /* IS_ENABLED(CONFIG_HYPERV) */
#endif /* __ARCH_X86_KVM_VMX_ONHYPERV_H__ */
+368
View File
@@ -0,0 +1,368 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_INSN_H
#define __KVM_X86_VMX_INSN_H
#include <linux/nospec.h>
#include <asm/vmx.h>
#include "vmx_onhyperv.h"
#include "vmcs.h"
#include "../x86.h"
void vmread_error(unsigned long field);
void vmwrite_error(unsigned long field, unsigned long value);
void vmclear_error(struct vmcs *vmcs, u64 phys_addr);
void vmptrld_error(struct vmcs *vmcs, u64 phys_addr);
void invvpid_error(unsigned long ext, u16 vpid, gva_t gva);
void invept_error(unsigned long ext, u64 eptp);
#ifndef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
/*
* The VMREAD error trampoline _always_ uses the stack to pass parameters, even
* for 64-bit targets. Preserving all registers allows the VMREAD inline asm
* blob to avoid clobbering GPRs, which in turn allows the compiler to better
* optimize sequences of VMREADs.
*
* Declare the trampoline as an opaque label as it's not safe to call from C
* code; there is no way to tell the compiler to pass params on the stack for
* 64-bit targets.
*
* void vmread_error_trampoline(unsigned long field, bool fault);
*/
extern unsigned long vmread_error_trampoline;
/*
* The second VMREAD error trampoline, called from the assembly trampoline,
* exists primarily to enable instrumentation for the VM-Fail path.
*/
void vmread_error_trampoline2(unsigned long field, bool fault);
#endif
static __always_inline void vmcs_check16(unsigned long field)
{
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000,
"16-bit accessor invalid for 64-bit field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
"16-bit accessor invalid for 64-bit high field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000,
"16-bit accessor invalid for 32-bit field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000,
"16-bit accessor invalid for natural width field");
}
static __always_inline void vmcs_check32(unsigned long field)
{
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0,
"32-bit accessor invalid for 16-bit field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000,
"32-bit accessor invalid for 64-bit field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
"32-bit accessor invalid for 64-bit high field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000,
"32-bit accessor invalid for natural width field");
}
static __always_inline void vmcs_check64(unsigned long field)
{
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0,
"64-bit accessor invalid for 16-bit field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
"64-bit accessor invalid for 64-bit high field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000,
"64-bit accessor invalid for 32-bit field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000,
"64-bit accessor invalid for natural width field");
}
static __always_inline void vmcs_checkl(unsigned long field)
{
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0,
"Natural width accessor invalid for 16-bit field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000,
"Natural width accessor invalid for 64-bit field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
"Natural width accessor invalid for 64-bit high field");
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000,
"Natural width accessor invalid for 32-bit field");
}
static __always_inline unsigned long __vmcs_readl(unsigned long field)
{
unsigned long value;
#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
asm_goto_output("1: vmread %[field], %[output]\n\t"
"jna %l[do_fail]\n\t"
_ASM_EXTABLE(1b, %l[do_exception])
: [output] "=r" (value)
: [field] "r" (field)
: "cc", "memory"
: do_fail, do_exception);
return value;
do_fail:
instrumentation_begin();
vmread_error(field);
instrumentation_end();
return 0;
do_exception:
kvm_spurious_fault();
return 0;
#else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
asm volatile("1: vmread %[field], %[output]\n\t"
"ja 3f\n\t"
/*
* VMREAD failed. Push '0' for @fault, push the failing
* @field, and bounce through the trampoline to preserve
* volatile registers.
*/
"xorl %k[output], %k[output]\n\t"
"2:\n\t"
"push %[output]\n\t"
"push %[field]\n\t"
"call vmread_error_trampoline\n\t"
/*
* Unwind the stack. Note, the trampoline zeros out the
* memory for @fault so that the result is '0' on error.
*/
"pop %[field]\n\t"
"pop %[output]\n\t"
"3:\n\t"
/* VMREAD faulted. As above, except push '1' for @fault. */
_ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_ONE_REG, %[output])
: ASM_CALL_CONSTRAINT, [output] "=&r" (value)
: [field] "r" (field)
: "cc", "memory");
return value;
#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
}
static __always_inline u16 vmcs_read16(unsigned long field)
{
vmcs_check16(field);
if (kvm_is_using_evmcs())
return evmcs_read16(field);
return __vmcs_readl(field);
}
static __always_inline u32 vmcs_read32(unsigned long field)
{
vmcs_check32(field);
if (kvm_is_using_evmcs())
return evmcs_read32(field);
return __vmcs_readl(field);
}
static __always_inline u64 vmcs_read64(unsigned long field)
{
vmcs_check64(field);
if (kvm_is_using_evmcs())
return evmcs_read64(field);
#ifdef CONFIG_X86_64
return __vmcs_readl(field);
#else
return __vmcs_readl(field) | ((u64)__vmcs_readl(field+1) << 32);
#endif
}
static __always_inline unsigned long vmcs_readl(unsigned long field)
{
vmcs_checkl(field);
if (kvm_is_using_evmcs())
return evmcs_read64(field);
return __vmcs_readl(field);
}
#define vmx_asm1(insn, op1, error_args...) \
do { \
asm goto("1: " __stringify(insn) " %0\n\t" \
"jna %l[error]\n\t" \
_ASM_EXTABLE(1b, %l[fault]) \
: : op1 : "cc", "memory" : error, fault); \
return; \
error: \
instrumentation_begin(); \
insn##_error(error_args); \
instrumentation_end(); \
return; \
fault: \
kvm_spurious_fault(); \
} while (0)
#define vmx_asm2(insn, op1, op2, error_args...) \
do { \
asm goto("1: " __stringify(insn) " %1, %0\n\t" \
"jna %l[error]\n\t" \
_ASM_EXTABLE(1b, %l[fault]) \
: : op1, op2 : "cc", "memory" : error, fault);\
return; \
error: \
instrumentation_begin(); \
insn##_error(error_args); \
instrumentation_end(); \
return; \
fault: \
kvm_spurious_fault(); \
} while (0)
static __always_inline void __vmcs_writel(unsigned long field, unsigned long value)
{
vmx_asm2(vmwrite, "r" (field), ASM_INPUT_RM (value), field, value);
}
static __always_inline void vmcs_write16(unsigned long field, u16 value)
{
vmcs_check16(field);
if (kvm_is_using_evmcs())
return evmcs_write16(field, value);
__vmcs_writel(field, value);
}
static __always_inline void vmcs_write32(unsigned long field, u32 value)
{
vmcs_check32(field);
if (kvm_is_using_evmcs())
return evmcs_write32(field, value);
__vmcs_writel(field, value);
}
static __always_inline void vmcs_write64(unsigned long field, u64 value)
{
vmcs_check64(field);
if (kvm_is_using_evmcs())
return evmcs_write64(field, value);
__vmcs_writel(field, value);
#ifndef CONFIG_X86_64
__vmcs_writel(field+1, value >> 32);
#endif
}
static __always_inline void vmcs_writel(unsigned long field, unsigned long value)
{
vmcs_checkl(field);
if (kvm_is_using_evmcs())
return evmcs_write64(field, value);
__vmcs_writel(field, value);
}
static __always_inline void vmcs_clear_bits(unsigned long field, u32 mask)
{
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000,
"vmcs_clear_bits does not support 64-bit fields");
if (kvm_is_using_evmcs())
return evmcs_write32(field, evmcs_read32(field) & ~mask);
__vmcs_writel(field, __vmcs_readl(field) & ~mask);
}
static __always_inline void vmcs_set_bits(unsigned long field, u32 mask)
{
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000,
"vmcs_set_bits does not support 64-bit fields");
if (kvm_is_using_evmcs())
return evmcs_write32(field, evmcs_read32(field) | mask);
__vmcs_writel(field, __vmcs_readl(field) | mask);
}
static inline void vmcs_clear(struct vmcs *vmcs)
{
u64 phys_addr = __pa(vmcs);
vmx_asm1(vmclear, "m"(phys_addr), vmcs, phys_addr);
}
static inline void vmcs_load(struct vmcs *vmcs)
{
u64 phys_addr = __pa(vmcs);
if (kvm_is_using_evmcs())
return evmcs_load(phys_addr);
vmx_asm1(vmptrld, "m"(phys_addr), vmcs, phys_addr);
}
static inline void __invvpid(unsigned long ext, u16 vpid, gva_t gva)
{
struct {
u64 vpid : 16;
u64 rsvd : 48;
u64 gva;
} operand = { vpid, 0, gva };
vmx_asm2(invvpid, "r"(ext), "m"(operand), ext, vpid, gva);
}
static inline void __invept(unsigned long ext, u64 eptp)
{
struct {
u64 eptp;
u64 reserved_0;
} operand = { eptp, 0 };
vmx_asm2(invept, "r"(ext), "m"(operand), ext, eptp);
}
static inline void vpid_sync_vcpu_single(int vpid)
{
if (vpid == 0)
return;
__invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vpid, 0);
}
static inline void vpid_sync_vcpu_global(void)
{
__invvpid(VMX_VPID_EXTENT_ALL_CONTEXT, 0, 0);
}
static inline void vpid_sync_context(int vpid)
{
if (cpu_has_vmx_invvpid_single())
vpid_sync_vcpu_single(vpid);
else if (vpid != 0)
vpid_sync_vcpu_global();
}
static inline void vpid_sync_vcpu_addr(int vpid, gva_t addr)
{
if (vpid == 0)
return;
if (cpu_has_vmx_invvpid_individual_addr())
__invvpid(VMX_VPID_EXTENT_INDIVIDUAL_ADDR, vpid, addr);
else
vpid_sync_context(vpid);
}
static inline void ept_sync_global(void)
{
__invept(VMX_EPT_EXTENT_GLOBAL, 0);
}
static inline void ept_sync_context(u64 eptp)
{
if (cpu_has_vmx_invept_context())
__invept(VMX_EPT_EXTENT_CONTEXT, eptp);
else
ept_sync_global();
}
#endif /* __KVM_X86_VMX_INSN_H */
+165
View File
@@ -0,0 +1,165 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_X86_OPS_H
#define __KVM_X86_VMX_X86_OPS_H
#include <linux/kvm_host.h>
#include "capabilities.h"
#include "x86.h"
__init int vmx_hardware_setup(void);
extern struct kvm_x86_ops vt_x86_ops __initdata;
extern struct kvm_x86_init_ops vt_init_ops __initdata;
void vmx_hardware_unsetup(void);
int vmx_check_processor_compat(void);
int vmx_enable_virtualization_cpu(void);
void vmx_disable_virtualization_cpu(void);
void vmx_emergency_disable_virtualization_cpu(void);
int vmx_vm_init(struct kvm *kvm);
void vmx_vm_destroy(struct kvm *kvm);
int vmx_vcpu_precreate(struct kvm *kvm);
int vmx_vcpu_create(struct kvm_vcpu *vcpu);
int vmx_vcpu_pre_run(struct kvm_vcpu *vcpu);
fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags);
void vmx_vcpu_free(struct kvm_vcpu *vcpu);
void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event);
void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
void vmx_vcpu_put(struct kvm_vcpu *vcpu);
int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath);
void vmx_handle_exit_irqoff(struct kvm_vcpu *vcpu);
int vmx_skip_emulated_instruction(struct kvm_vcpu *vcpu);
void vmx_update_emulated_instruction(struct kvm_vcpu *vcpu);
int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
#ifdef CONFIG_KVM_SMM
int vmx_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection);
int vmx_enter_smm(struct kvm_vcpu *vcpu, union kvm_smram *smram);
int vmx_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram);
void vmx_enable_smi_window(struct kvm_vcpu *vcpu);
#endif
int vmx_check_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
void *insn, int insn_len);
int vmx_check_intercept(struct kvm_vcpu *vcpu,
struct x86_instruction_info *info,
enum x86_intercept_stage stage,
struct x86_exception *exception);
bool vmx_apic_init_signal_blocked(struct kvm_vcpu *vcpu);
void vmx_migrate_timers(struct kvm_vcpu *vcpu);
void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu);
void vmx_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr);
int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu);
void vmx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
int trig_mode, int vector);
void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu);
bool vmx_has_emulated_msr(struct kvm *kvm, u32 index);
void vmx_recalc_intercepts(struct kvm_vcpu *vcpu);
void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu);
void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu);
int vmx_get_feature_msr(u32 msr, u64 *data);
int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
#define vmx_complete_emulated_msr kvm_complete_insn_gp
u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg);
void vmx_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
void vmx_set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
int vmx_get_cpl(struct kvm_vcpu *vcpu);
void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
bool vmx_is_valid_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
void vmx_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level);
void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
bool vmx_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
int vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer);
void vmx_get_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
void vmx_set_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
void vmx_get_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
void vmx_set_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val);
void vmx_sync_dirty_debug_regs(struct kvm_vcpu *vcpu);
void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg);
unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu);
void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
bool vmx_get_if_flag(struct kvm_vcpu *vcpu);
void vmx_flush_tlb_all(struct kvm_vcpu *vcpu);
void vmx_flush_tlb_current(struct kvm_vcpu *vcpu);
void vmx_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr, bool *full);
void vmx_flush_tlb_guest(struct kvm_vcpu *vcpu);
void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask);
u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu);
void vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall);
void vmx_inject_irq(struct kvm_vcpu *vcpu, bool reinjected);
void vmx_inject_nmi(struct kvm_vcpu *vcpu);
void vmx_inject_exception(struct kvm_vcpu *vcpu);
void vmx_cancel_injection(struct kvm_vcpu *vcpu);
int vmx_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection);
int vmx_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection);
bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu);
void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked);
void vmx_enable_nmi_window(struct kvm_vcpu *vcpu);
void vmx_enable_irq_window(struct kvm_vcpu *vcpu);
void vmx_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr);
void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu);
void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu);
void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr);
int vmx_set_identity_map_addr(struct kvm *kvm, u64 ident_addr);
u8 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio);
static inline bool vmx_tdp_has_smep(struct kvm *kvm)
{
return enable_mbec;
}
void vmx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code);
void vmx_get_entry_info(struct kvm_vcpu *vcpu, u32 *intr_info, u32 *error_code);
u64 vmx_get_l2_tsc_offset(struct kvm_vcpu *vcpu);
u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu);
void vmx_write_tsc_offset(struct kvm_vcpu *vcpu);
void vmx_write_tsc_multiplier(struct kvm_vcpu *vcpu);
void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu);
#ifdef CONFIG_X86_64
int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc,
bool *expired);
void vmx_cancel_hv_timer(struct kvm_vcpu *vcpu);
#endif
void vmx_setup_mce(struct kvm_vcpu *vcpu);
#ifdef CONFIG_KVM_INTEL_TDX
void tdx_disable_virtualization_cpu(void);
int tdx_vm_init(struct kvm *kvm);
void tdx_mmu_release_hkid(struct kvm *kvm);
void tdx_vm_destroy(struct kvm *kvm);
int tdx_vm_ioctl(struct kvm *kvm, void __user *argp);
int tdx_vcpu_create(struct kvm_vcpu *vcpu);
void tdx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event);
void tdx_vcpu_free(struct kvm_vcpu *vcpu);
void tdx_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
int tdx_vcpu_pre_run(struct kvm_vcpu *vcpu);
fastpath_t tdx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags);
void tdx_prepare_switch_to_guest(struct kvm_vcpu *vcpu);
void tdx_vcpu_put(struct kvm_vcpu *vcpu);
int tdx_handle_exit(struct kvm_vcpu *vcpu,
enum exit_fastpath_completion fastpath);
void tdx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
int trig_mode, int vector);
void tdx_inject_nmi(struct kvm_vcpu *vcpu);
void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code);
bool tdx_has_emulated_msr(u32 index);
int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr);
int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr);
int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp);
int tdx_vcpu_unlocked_ioctl(struct kvm_vcpu *vcpu, void __user *argp);
void tdx_flush_tlb_current(struct kvm_vcpu *vcpu);
void tdx_flush_tlb_all(struct kvm_vcpu *vcpu);
void tdx_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level);
int tdx_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, bool is_private);
#endif
#endif /* __KVM_X86_VMX_X86_OPS_H */