mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'kvm-x86-nested-7.1' of https://github.com/kvm-x86/linux into HEAD
KVM nested SVM changes for 7.1 (with one common x86 fix)
- To minimize the probability of corrupting guest state, defer KVM's
non-architectural delivery of exception payloads (e.g. CR2 and DR6) until
consumption of the payload is imminent, and force delivery of the payload
in all paths where userspace saves relevant state.
- Use vcpu->arch.cr2 when updating vmcb12's CR2 on nested #VMEXIT to fix a
bug where L2's CR2 can get corrupted after a save/restore, e.g. if the VM
is migrated while L2 is faulting in memory.
- Fix a class of nSVM bugs where some fields written by the CPU are not
synchronized from vmcb02 to cached vmcb12 after VMRUN, and so are not
up-to-date when saved by KVM_GET_NESTED_STATE.
- Fix a class of bugs where the ordering between KVM_SET_NESTED_STATE and
KVM_SET_{S}REGS could cause vmcb02 to be incorrectly initialized after
save+restore.
- Add a variety of missing nSVM consistency checks.
- Fix several bugs where KVM failed to correctly update VMCB fields on nested
#VMEXIT.
- Fix several bugs where KVM failed to correctly synthesize #UD or #GP for
SVM-related instructions.
- Add support for save+restore of virtualized LBRs (on SVM).
- Refactor various helpers and macros to improve clarity and (hopefully) make
the code easier to maintain.
- Aggressively sanitize fields when copying from vmcb12 to guard against
unintentionally allowing L1 to utilize yet-to-be-defined features.
- Fix several bugs where KVM botched rAX legality checks when emulating SVM
instructions. Note, KVM is still flawed in that KVM doesn't address size
prefix overrides for 64-bit guests; this should probably be documented as a
KVM erratum.
- Fail emulation of VMRUN/VMLOAD/VMSAVE if mapping vmcb12 fails instead of
somewhat arbitrarily synthesizing #GP (i.e. don't bastardize AMD's already-
sketchy behavior of generating #GP if for "unsupported" addresses).
- Cache all used vmcb12 fields to further harden against TOCTOU bugs.
This commit is contained in:
@@ -1098,6 +1098,21 @@ struct kvm_vcpu_arch {
|
||||
*/
|
||||
bool pdptrs_from_userspace;
|
||||
|
||||
/*
|
||||
* Set if an emulated nested VM-Enter to L2 is pending completion. KVM
|
||||
* must not synthesize a VM-Exit to L1 before entering L2, as VM-Exits
|
||||
* can only occur at instruction boundaries. The only exception is
|
||||
* VMX's "notify" exits, which exist in large part to break the CPU out
|
||||
* of infinite ucode loops, but can corrupt vCPU state in the process!
|
||||
*
|
||||
* For all intents and purposes, this is a boolean, but it's tracked as
|
||||
* a u8 so that KVM can detect when userspace may have stuffed vCPU
|
||||
* state and generated an architecturally-impossible VM-Exit.
|
||||
*/
|
||||
#define KVM_NESTED_RUN_PENDING 1
|
||||
#define KVM_NESTED_RUN_PENDING_UNTRUSTED 2
|
||||
u8 nested_run_pending;
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
hpa_t hv_root_tdp;
|
||||
#endif
|
||||
|
||||
@@ -142,13 +142,13 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
|
||||
u64 exit_info_2;
|
||||
u32 exit_int_info;
|
||||
u32 exit_int_info_err;
|
||||
u64 nested_ctl;
|
||||
u64 misc_ctl;
|
||||
u64 avic_vapic_bar;
|
||||
u64 ghcb_gpa;
|
||||
u32 event_inj;
|
||||
u32 event_inj_err;
|
||||
u64 nested_cr3;
|
||||
u64 virt_ext;
|
||||
u64 misc_ctl2;
|
||||
u32 clean;
|
||||
u32 reserved_5;
|
||||
u64 next_rip;
|
||||
@@ -182,6 +182,8 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
|
||||
#define TLB_CONTROL_FLUSH_ASID 3
|
||||
#define TLB_CONTROL_FLUSH_ASID_LOCAL 7
|
||||
|
||||
#define TLB_CONTROL_MASK GENMASK(2, 0)
|
||||
|
||||
#define ERAP_CONTROL_ALLOW_LARGER_RAP BIT(0)
|
||||
#define ERAP_CONTROL_CLEAR_RAP BIT(1)
|
||||
|
||||
@@ -222,8 +224,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
|
||||
#define X2APIC_MODE_SHIFT 30
|
||||
#define X2APIC_MODE_MASK (1 << X2APIC_MODE_SHIFT)
|
||||
|
||||
#define LBR_CTL_ENABLE_MASK BIT_ULL(0)
|
||||
#define VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK BIT_ULL(1)
|
||||
#define SVM_INT_VECTOR_MASK GENMASK(7, 0)
|
||||
|
||||
#define SVM_INTERRUPT_SHADOW_MASK BIT_ULL(0)
|
||||
#define SVM_GUEST_INTERRUPT_MASK BIT_ULL(1)
|
||||
@@ -239,10 +240,12 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
|
||||
#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT)
|
||||
#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT)
|
||||
|
||||
#define SVM_NESTED_CTL_NP_ENABLE BIT(0)
|
||||
#define SVM_NESTED_CTL_SEV_ENABLE BIT(1)
|
||||
#define SVM_NESTED_CTL_SEV_ES_ENABLE BIT(2)
|
||||
#define SVM_MISC_ENABLE_NP BIT(0)
|
||||
#define SVM_MISC_ENABLE_SEV BIT(1)
|
||||
#define SVM_MISC_ENABLE_SEV_ES BIT(2)
|
||||
|
||||
#define SVM_MISC2_ENABLE_V_LBR BIT_ULL(0)
|
||||
#define SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE BIT_ULL(1)
|
||||
|
||||
#define SVM_TSC_RATIO_RSVD 0xffffff0000000000ULL
|
||||
#define SVM_TSC_RATIO_MIN 0x0000000000000001ULL
|
||||
@@ -636,6 +639,9 @@ static inline void __unused_size_checks(void)
|
||||
#define SVM_EVTINJ_VALID (1 << 31)
|
||||
#define SVM_EVTINJ_VALID_ERR (1 << 11)
|
||||
|
||||
#define SVM_EVTINJ_RESERVED_BITS ~(SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | \
|
||||
SVM_EVTINJ_VALID_ERR | SVM_EVTINJ_VALID)
|
||||
|
||||
#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
|
||||
#define SVM_EXITINTINFO_TYPE_MASK SVM_EVTINJ_TYPE_MASK
|
||||
|
||||
|
||||
@@ -3887,8 +3887,7 @@ static int check_svme_pa(struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
u64 rax = reg_read(ctxt, VCPU_REGS_RAX);
|
||||
|
||||
/* Valid physical address? */
|
||||
if (rax & 0xffff000000000000ULL)
|
||||
if (!ctxt->ops->page_address_valid(ctxt, rax))
|
||||
return emulate_gp(ctxt, 0);
|
||||
|
||||
return check_svme(ctxt);
|
||||
|
||||
@@ -305,14 +305,6 @@ static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline bool kvm_hv_is_tlb_flush_hcall(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline bool guest_hv_cpuid_has_l2_tlb_flush(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -245,6 +245,8 @@ struct x86_emulate_ops {
|
||||
|
||||
bool (*is_canonical_addr)(struct x86_emulate_ctxt *ctxt, gva_t addr,
|
||||
unsigned int flags);
|
||||
|
||||
bool (*page_address_valid)(struct x86_emulate_ctxt *ctxt, gpa_t gpa);
|
||||
};
|
||||
|
||||
/* Type, address-of, and value of an instruction's operand. */
|
||||
|
||||
@@ -41,10 +41,17 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
|
||||
return hv_vcpu->vp_assist_page.nested_control.features.directhypercall;
|
||||
}
|
||||
|
||||
static inline bool nested_svm_is_l2_tlb_flush_hcall(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return guest_hv_cpuid_has_l2_tlb_flush(vcpu) &&
|
||||
nested_svm_l2_tlb_flush_enabled(vcpu) &&
|
||||
kvm_hv_is_tlb_flush_hcall(vcpu);
|
||||
}
|
||||
|
||||
void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
|
||||
#else /* CONFIG_KVM_HYPERV */
|
||||
static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) {}
|
||||
static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
|
||||
static inline bool nested_svm_is_l2_tlb_flush_hcall(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
+363
-260
File diff suppressed because it is too large
Load Diff
@@ -4591,7 +4591,7 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm, bool init_event)
|
||||
struct kvm_sev_info *sev = to_kvm_sev_info(svm->vcpu.kvm);
|
||||
struct vmcb *vmcb = svm->vmcb01.ptr;
|
||||
|
||||
svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ES_ENABLE;
|
||||
svm->vmcb->control.misc_ctl |= SVM_MISC_ENABLE_SEV_ES;
|
||||
|
||||
/*
|
||||
* An SEV-ES guest requires a VMSA area that is a separate from the
|
||||
@@ -4631,7 +4631,7 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm, bool init_event)
|
||||
if (!sev_vcpu_has_debug_swap(svm)) {
|
||||
vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ);
|
||||
vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE);
|
||||
recalc_intercepts(svm);
|
||||
svm_mark_intercepts_dirty(svm);
|
||||
} else {
|
||||
/*
|
||||
* Disable #DB intercept iff DebugSwap is enabled. KVM doesn't
|
||||
@@ -4662,7 +4662,7 @@ void sev_init_vmcb(struct vcpu_svm *svm, bool init_event)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = &svm->vcpu;
|
||||
|
||||
svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ENABLE;
|
||||
svm->vmcb->control.misc_ctl |= SVM_MISC_ENABLE_SEV;
|
||||
clr_exception_intercept(svm, UD_VECTOR);
|
||||
|
||||
/*
|
||||
|
||||
+236
-117
File diff suppressed because it is too large
Load Diff
+59
-22
@@ -140,12 +140,32 @@ struct kvm_vmcb_info {
|
||||
};
|
||||
|
||||
struct vmcb_save_area_cached {
|
||||
struct vmcb_seg es;
|
||||
struct vmcb_seg cs;
|
||||
struct vmcb_seg ss;
|
||||
struct vmcb_seg ds;
|
||||
struct vmcb_seg gdtr;
|
||||
struct vmcb_seg idtr;
|
||||
u8 cpl;
|
||||
u64 efer;
|
||||
u64 cr4;
|
||||
u64 cr3;
|
||||
u64 cr0;
|
||||
u64 dr7;
|
||||
u64 dr6;
|
||||
u64 rflags;
|
||||
u64 rip;
|
||||
u64 rsp;
|
||||
u64 s_cet;
|
||||
u64 ssp;
|
||||
u64 isst_addr;
|
||||
u64 rax;
|
||||
u64 cr2;
|
||||
u64 dbgctl;
|
||||
u64 br_from;
|
||||
u64 br_to;
|
||||
u64 last_excp_from;
|
||||
u64 last_excp_to;
|
||||
};
|
||||
|
||||
struct vmcb_ctrl_area_cached {
|
||||
@@ -166,14 +186,13 @@ struct vmcb_ctrl_area_cached {
|
||||
u64 exit_info_2;
|
||||
u32 exit_int_info;
|
||||
u32 exit_int_info_err;
|
||||
u64 nested_ctl;
|
||||
u64 misc_ctl;
|
||||
u32 event_inj;
|
||||
u32 event_inj_err;
|
||||
u64 next_rip;
|
||||
u64 nested_cr3;
|
||||
u64 virt_ext;
|
||||
u64 misc_ctl2;
|
||||
u32 clean;
|
||||
u64 bus_lock_rip;
|
||||
union {
|
||||
#if IS_ENABLED(CONFIG_HYPERV) || IS_ENABLED(CONFIG_KVM_HYPERV)
|
||||
struct hv_vmcb_enlightenments hv_enlightenments;
|
||||
@@ -188,6 +207,7 @@ struct svm_nested_state {
|
||||
u64 vm_cr_msr;
|
||||
u64 vmcb12_gpa;
|
||||
u64 last_vmcb12_gpa;
|
||||
u64 last_bus_lock_rip;
|
||||
|
||||
/*
|
||||
* The MSR permissions map used for vmcb02, which is the merge result
|
||||
@@ -195,10 +215,6 @@ struct svm_nested_state {
|
||||
*/
|
||||
void *msrpm;
|
||||
|
||||
/* A VMRUN has started but has not yet been performed, so
|
||||
* we cannot inject a nested vmexit yet. */
|
||||
bool nested_run_pending;
|
||||
|
||||
/* cache for control fields of the guest */
|
||||
struct vmcb_ctrl_area_cached ctl;
|
||||
|
||||
@@ -357,8 +373,6 @@ struct svm_cpu_data {
|
||||
|
||||
DECLARE_PER_CPU(struct svm_cpu_data, svm_data);
|
||||
|
||||
void recalc_intercepts(struct vcpu_svm *svm);
|
||||
|
||||
static __always_inline struct kvm_svm *to_kvm_svm(struct kvm *kvm)
|
||||
{
|
||||
return container_of(kvm, struct kvm_svm, kvm);
|
||||
@@ -415,9 +429,9 @@ static inline void vmcb_mark_dirty(struct vmcb *vmcb, int bit)
|
||||
vmcb->control.clean &= ~(1 << bit);
|
||||
}
|
||||
|
||||
static inline bool vmcb_is_dirty(struct vmcb *vmcb, int bit)
|
||||
static inline bool vmcb12_is_dirty(struct vmcb_ctrl_area_cached *control, int bit)
|
||||
{
|
||||
return !test_bit(bit, (unsigned long *)&vmcb->control.clean);
|
||||
return !test_bit(bit, (unsigned long *)&control->clean);
|
||||
}
|
||||
|
||||
static __always_inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
|
||||
@@ -486,6 +500,22 @@ static inline bool vmcb12_is_intercept(struct vmcb_ctrl_area_cached *control, u3
|
||||
return __vmcb_is_intercept((unsigned long *)&control->intercepts, bit);
|
||||
}
|
||||
|
||||
void nested_vmcb02_recalc_intercepts(struct vcpu_svm *svm);
|
||||
|
||||
static inline void svm_mark_intercepts_dirty(struct vcpu_svm *svm)
|
||||
{
|
||||
vmcb_mark_dirty(svm->vmcb01.ptr, VMCB_INTERCEPTS);
|
||||
|
||||
/*
|
||||
* If L2 is active, recalculate the intercepts for vmcb02 to account
|
||||
* for the changes made to vmcb01. All intercept configuration is done
|
||||
* for vmcb01 and then propagated to vmcb02 to combine KVM's intercepts
|
||||
* with L1's intercepts (from the vmcb12 snapshot).
|
||||
*/
|
||||
if (is_guest_mode(&svm->vcpu))
|
||||
nested_vmcb02_recalc_intercepts(svm);
|
||||
}
|
||||
|
||||
static inline void set_exception_intercept(struct vcpu_svm *svm, u32 bit)
|
||||
{
|
||||
struct vmcb *vmcb = svm->vmcb01.ptr;
|
||||
@@ -493,7 +523,7 @@ static inline void set_exception_intercept(struct vcpu_svm *svm, u32 bit)
|
||||
WARN_ON_ONCE(bit >= 32);
|
||||
vmcb_set_intercept(&vmcb->control, INTERCEPT_EXCEPTION_OFFSET + bit);
|
||||
|
||||
recalc_intercepts(svm);
|
||||
svm_mark_intercepts_dirty(svm);
|
||||
}
|
||||
|
||||
static inline void clr_exception_intercept(struct vcpu_svm *svm, u32 bit)
|
||||
@@ -503,7 +533,7 @@ static inline void clr_exception_intercept(struct vcpu_svm *svm, u32 bit)
|
||||
WARN_ON_ONCE(bit >= 32);
|
||||
vmcb_clr_intercept(&vmcb->control, INTERCEPT_EXCEPTION_OFFSET + bit);
|
||||
|
||||
recalc_intercepts(svm);
|
||||
svm_mark_intercepts_dirty(svm);
|
||||
}
|
||||
|
||||
static inline void svm_set_intercept(struct vcpu_svm *svm, int bit)
|
||||
@@ -512,7 +542,7 @@ static inline void svm_set_intercept(struct vcpu_svm *svm, int bit)
|
||||
|
||||
vmcb_set_intercept(&vmcb->control, bit);
|
||||
|
||||
recalc_intercepts(svm);
|
||||
svm_mark_intercepts_dirty(svm);
|
||||
}
|
||||
|
||||
static inline void svm_clr_intercept(struct vcpu_svm *svm, int bit)
|
||||
@@ -521,7 +551,7 @@ static inline void svm_clr_intercept(struct vcpu_svm *svm, int bit)
|
||||
|
||||
vmcb_clr_intercept(&vmcb->control, bit);
|
||||
|
||||
recalc_intercepts(svm);
|
||||
svm_mark_intercepts_dirty(svm);
|
||||
}
|
||||
|
||||
static inline bool svm_is_intercept(struct vcpu_svm *svm, int bit)
|
||||
@@ -578,7 +608,7 @@ static inline bool gif_set(struct vcpu_svm *svm)
|
||||
|
||||
static inline bool nested_npt_enabled(struct vcpu_svm *svm)
|
||||
{
|
||||
return svm->nested.ctl.nested_ctl & SVM_NESTED_CTL_NP_ENABLE;
|
||||
return svm->nested.ctl.misc_ctl & SVM_MISC_ENABLE_NP;
|
||||
}
|
||||
|
||||
static inline bool nested_vnmi_enabled(struct vcpu_svm *svm)
|
||||
@@ -713,8 +743,16 @@ static inline void *svm_vcpu_alloc_msrpm(void)
|
||||
return svm_alloc_permissions_map(MSRPM_SIZE, GFP_KERNEL_ACCOUNT);
|
||||
}
|
||||
|
||||
#define svm_copy_lbrs(to, from) \
|
||||
do { \
|
||||
(to)->dbgctl = (from)->dbgctl; \
|
||||
(to)->br_from = (from)->br_from; \
|
||||
(to)->br_to = (from)->br_to; \
|
||||
(to)->last_excp_from = (from)->last_excp_from; \
|
||||
(to)->last_excp_to = (from)->last_excp_to; \
|
||||
} while (0)
|
||||
|
||||
void svm_vcpu_free_msrpm(void *msrpm);
|
||||
void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb);
|
||||
void svm_enable_lbrv(struct kvm_vcpu *vcpu);
|
||||
void svm_update_lbrv(struct kvm_vcpu *vcpu);
|
||||
|
||||
@@ -776,8 +814,7 @@ static inline bool nested_exit_on_nmi(struct vcpu_svm *svm)
|
||||
|
||||
int __init nested_svm_init_msrpm_merge_offsets(void);
|
||||
|
||||
int enter_svm_guest_mode(struct kvm_vcpu *vcpu,
|
||||
u64 vmcb_gpa, struct vmcb *vmcb12, bool from_vmrun);
|
||||
int enter_svm_guest_mode(struct kvm_vcpu *vcpu, u64 vmcb_gpa, bool from_vmrun);
|
||||
void svm_leave_nested(struct kvm_vcpu *vcpu);
|
||||
void svm_free_nested(struct vcpu_svm *svm);
|
||||
int svm_allocate_nested(struct vcpu_svm *svm);
|
||||
@@ -785,14 +822,14 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu);
|
||||
void svm_copy_vmrun_state(struct vmcb_save_area *to_save,
|
||||
struct vmcb_save_area *from_save);
|
||||
void svm_copy_vmloadsave_state(struct vmcb *to_vmcb, struct vmcb *from_vmcb);
|
||||
int nested_svm_vmexit(struct vcpu_svm *svm);
|
||||
void nested_svm_vmexit(struct vcpu_svm *svm);
|
||||
|
||||
static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
|
||||
static inline void nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
|
||||
{
|
||||
svm->vmcb->control.exit_code = exit_code;
|
||||
svm->vmcb->control.exit_info_1 = 0;
|
||||
svm->vmcb->control.exit_info_2 = 0;
|
||||
return nested_svm_vmexit(svm);
|
||||
nested_svm_vmexit(svm);
|
||||
}
|
||||
|
||||
int nested_svm_exit_handled(struct vcpu_svm *svm);
|
||||
|
||||
+26
-24
@@ -2273,7 +2273,7 @@ static void vmx_start_preemption_timer(struct kvm_vcpu *vcpu,
|
||||
|
||||
static u64 nested_vmx_calc_efer(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
|
||||
{
|
||||
if (vmx->nested.nested_run_pending &&
|
||||
if (vmx->vcpu.arch.nested_run_pending &&
|
||||
(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER))
|
||||
return vmcs12->guest_ia32_efer;
|
||||
else if (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE)
|
||||
@@ -2513,7 +2513,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
|
||||
/*
|
||||
* Interrupt/Exception Fields
|
||||
*/
|
||||
if (vmx->nested.nested_run_pending) {
|
||||
if (vmx->vcpu.arch.nested_run_pending) {
|
||||
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
|
||||
vmcs12->vm_entry_intr_info_field);
|
||||
vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
|
||||
@@ -2621,7 +2621,7 @@ static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
|
||||
vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3);
|
||||
}
|
||||
|
||||
if (kvm_mpx_supported() && vmx->nested.nested_run_pending &&
|
||||
if (kvm_mpx_supported() && vmx->vcpu.arch.nested_run_pending &&
|
||||
(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))
|
||||
vmcs_write64(GUEST_BNDCFGS, vmcs12->guest_bndcfgs);
|
||||
}
|
||||
@@ -2718,7 +2718,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
|
||||
!(evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
|
||||
}
|
||||
|
||||
if (vmx->nested.nested_run_pending &&
|
||||
if (vcpu->arch.nested_run_pending &&
|
||||
(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) {
|
||||
kvm_set_dr(vcpu, 7, vmcs12->guest_dr7);
|
||||
vmx_guest_debugctl_write(vcpu, vmcs12->guest_ia32_debugctl &
|
||||
@@ -2728,13 +2728,13 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
|
||||
vmx_guest_debugctl_write(vcpu, vmx->nested.pre_vmenter_debugctl);
|
||||
}
|
||||
|
||||
if (!vmx->nested.nested_run_pending ||
|
||||
if (!vcpu->arch.nested_run_pending ||
|
||||
!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_CET_STATE))
|
||||
vmcs_write_cet_state(vcpu, vmx->nested.pre_vmenter_s_cet,
|
||||
vmx->nested.pre_vmenter_ssp,
|
||||
vmx->nested.pre_vmenter_ssp_tbl);
|
||||
|
||||
if (kvm_mpx_supported() && (!vmx->nested.nested_run_pending ||
|
||||
if (kvm_mpx_supported() && (!vcpu->arch.nested_run_pending ||
|
||||
!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)))
|
||||
vmcs_write64(GUEST_BNDCFGS, vmx->nested.pre_vmenter_bndcfgs);
|
||||
vmx_set_rflags(vcpu, vmcs12->guest_rflags);
|
||||
@@ -2747,7 +2747,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
|
||||
vcpu->arch.cr0_guest_owned_bits &= ~vmcs12->cr0_guest_host_mask;
|
||||
vmcs_writel(CR0_GUEST_HOST_MASK, ~vcpu->arch.cr0_guest_owned_bits);
|
||||
|
||||
if (vmx->nested.nested_run_pending &&
|
||||
if (vcpu->arch.nested_run_pending &&
|
||||
(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT)) {
|
||||
vmcs_write64(GUEST_IA32_PAT, vmcs12->guest_ia32_pat);
|
||||
vcpu->arch.pat = vmcs12->guest_ia32_pat;
|
||||
@@ -3349,7 +3349,7 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
|
||||
* to bit 8 (LME) if bit 31 in the CR0 field (corresponding to
|
||||
* CR0.PG) is 1.
|
||||
*/
|
||||
if (to_vmx(vcpu)->nested.nested_run_pending &&
|
||||
if (vcpu->arch.nested_run_pending &&
|
||||
(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER)) {
|
||||
if (CC(!kvm_valid_efer(vcpu, vmcs12->guest_ia32_efer)) ||
|
||||
CC(ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA)) ||
|
||||
@@ -3627,15 +3627,15 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
|
||||
|
||||
kvm_service_local_tlb_flush_requests(vcpu);
|
||||
|
||||
if (!vmx->nested.nested_run_pending ||
|
||||
if (!vcpu->arch.nested_run_pending ||
|
||||
!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
|
||||
vmx->nested.pre_vmenter_debugctl = vmx_guest_debugctl_read();
|
||||
if (kvm_mpx_supported() &&
|
||||
(!vmx->nested.nested_run_pending ||
|
||||
(!vcpu->arch.nested_run_pending ||
|
||||
!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)))
|
||||
vmx->nested.pre_vmenter_bndcfgs = vmcs_read64(GUEST_BNDCFGS);
|
||||
|
||||
if (!vmx->nested.nested_run_pending ||
|
||||
if (!vcpu->arch.nested_run_pending ||
|
||||
!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_CET_STATE))
|
||||
vmcs_read_cet_state(vcpu, &vmx->nested.pre_vmenter_s_cet,
|
||||
&vmx->nested.pre_vmenter_ssp,
|
||||
@@ -3844,7 +3844,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
||||
* We're finally done with prerequisite checking, and can start with
|
||||
* the nested entry.
|
||||
*/
|
||||
vmx->nested.nested_run_pending = 1;
|
||||
vcpu->arch.nested_run_pending = KVM_NESTED_RUN_PENDING;
|
||||
vmx->nested.has_preemption_timer_deadline = false;
|
||||
status = nested_vmx_enter_non_root_mode(vcpu, true);
|
||||
if (unlikely(status != NVMX_VMENTRY_SUCCESS))
|
||||
@@ -3876,12 +3876,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
||||
!nested_cpu_has(vmcs12, CPU_BASED_NMI_WINDOW_EXITING) &&
|
||||
!(nested_cpu_has(vmcs12, CPU_BASED_INTR_WINDOW_EXITING) &&
|
||||
(vmcs12->guest_rflags & X86_EFLAGS_IF))) {
|
||||
vmx->nested.nested_run_pending = 0;
|
||||
vcpu->arch.nested_run_pending = 0;
|
||||
return kvm_emulate_halt_noskip(vcpu);
|
||||
}
|
||||
break;
|
||||
case GUEST_ACTIVITY_WAIT_SIPI:
|
||||
vmx->nested.nested_run_pending = 0;
|
||||
vcpu->arch.nested_run_pending = 0;
|
||||
kvm_set_mp_state(vcpu, KVM_MP_STATE_INIT_RECEIVED);
|
||||
break;
|
||||
default:
|
||||
@@ -3891,7 +3891,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
||||
return 1;
|
||||
|
||||
vmentry_failed:
|
||||
vmx->nested.nested_run_pending = 0;
|
||||
vcpu->arch.nested_run_pending = 0;
|
||||
if (status == NVMX_VMENTRY_KVM_INTERNAL_ERROR)
|
||||
return 0;
|
||||
if (status == NVMX_VMENTRY_VMEXIT)
|
||||
@@ -4288,7 +4288,7 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu)
|
||||
* previously injected event, the pending exception occurred while said
|
||||
* event was being delivered and thus needs to be handled.
|
||||
*/
|
||||
bool block_nested_exceptions = vmx->nested.nested_run_pending;
|
||||
bool block_nested_exceptions = vcpu->arch.nested_run_pending;
|
||||
/*
|
||||
* Events that don't require injection, i.e. that are virtualized by
|
||||
* hardware, aren't blocked by a pending VM-Enter as KVM doesn't need
|
||||
@@ -4657,7 +4657,7 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
||||
|
||||
if (nested_cpu_has_preemption_timer(vmcs12) &&
|
||||
vmcs12->vm_exit_controls & VM_EXIT_SAVE_VMX_PREEMPTION_TIMER &&
|
||||
!vmx->nested.nested_run_pending)
|
||||
!vcpu->arch.nested_run_pending)
|
||||
vmcs12->vmx_preemption_timer_value =
|
||||
vmx_get_preemption_timer_value(vcpu);
|
||||
|
||||
@@ -5056,7 +5056,7 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
|
||||
vmx->nested.mtf_pending = false;
|
||||
|
||||
/* trying to cancel vmlaunch/vmresume is a bug */
|
||||
WARN_ON_ONCE(vmx->nested.nested_run_pending);
|
||||
kvm_warn_on_nested_run_pending(vcpu);
|
||||
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
|
||||
@@ -6679,7 +6679,7 @@ bool nested_vmx_reflect_vmexit(struct kvm_vcpu *vcpu)
|
||||
unsigned long exit_qual;
|
||||
u32 exit_intr_info;
|
||||
|
||||
WARN_ON_ONCE(vmx->nested.nested_run_pending);
|
||||
kvm_warn_on_nested_run_pending(vcpu);
|
||||
|
||||
/*
|
||||
* Late nested VM-Fail shares the same flow as nested VM-Exit since KVM
|
||||
@@ -6775,7 +6775,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
|
||||
if (is_guest_mode(vcpu)) {
|
||||
kvm_state.flags |= KVM_STATE_NESTED_GUEST_MODE;
|
||||
|
||||
if (vmx->nested.nested_run_pending)
|
||||
if (vcpu->arch.nested_run_pending)
|
||||
kvm_state.flags |= KVM_STATE_NESTED_RUN_PENDING;
|
||||
|
||||
if (vmx->nested.mtf_pending)
|
||||
@@ -6850,7 +6850,7 @@ out:
|
||||
void vmx_leave_nested(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (is_guest_mode(vcpu)) {
|
||||
to_vmx(vcpu)->nested.nested_run_pending = 0;
|
||||
vcpu->arch.nested_run_pending = 0;
|
||||
nested_vmx_vmexit(vcpu, -1, 0, 0);
|
||||
}
|
||||
free_nested(vcpu);
|
||||
@@ -7008,8 +7008,10 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
|
||||
if (!(kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE))
|
||||
return 0;
|
||||
|
||||
vmx->nested.nested_run_pending =
|
||||
!!(kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING);
|
||||
if (kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING)
|
||||
vcpu->arch.nested_run_pending = KVM_NESTED_RUN_PENDING_UNTRUSTED;
|
||||
else
|
||||
vcpu->arch.nested_run_pending = 0;
|
||||
|
||||
vmx->nested.mtf_pending =
|
||||
!!(kvm_state->flags & KVM_STATE_NESTED_MTF_PENDING);
|
||||
@@ -7054,7 +7056,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
|
||||
return 0;
|
||||
|
||||
error_guest_mode:
|
||||
vmx->nested.nested_run_pending = 0;
|
||||
vcpu->arch.nested_run_pending = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -5279,7 +5279,7 @@ bool vmx_nmi_blocked(struct kvm_vcpu *vcpu)
|
||||
|
||||
int vmx_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
|
||||
{
|
||||
if (to_vmx(vcpu)->nested.nested_run_pending)
|
||||
if (vcpu->arch.nested_run_pending)
|
||||
return -EBUSY;
|
||||
|
||||
/* An NMI must not be injected into L2 if it's supposed to VM-Exit. */
|
||||
@@ -5306,7 +5306,7 @@ bool vmx_interrupt_blocked(struct kvm_vcpu *vcpu)
|
||||
|
||||
int vmx_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
|
||||
{
|
||||
if (to_vmx(vcpu)->nested.nested_run_pending)
|
||||
if (vcpu->arch.nested_run_pending)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
@@ -6118,7 +6118,7 @@ static bool vmx_unhandleable_emulation_required(struct kvm_vcpu *vcpu)
|
||||
* only reachable if userspace modifies L2 guest state after KVM has
|
||||
* performed the nested VM-Enter consistency checks.
|
||||
*/
|
||||
if (vmx->nested.nested_run_pending)
|
||||
if (vcpu->arch.nested_run_pending)
|
||||
return true;
|
||||
|
||||
/*
|
||||
@@ -6802,7 +6802,7 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
|
||||
* invalid guest state should never happen as that means KVM knowingly
|
||||
* allowed a nested VM-Enter with an invalid vmcs12. More below.
|
||||
*/
|
||||
if (KVM_BUG_ON(vmx->nested.nested_run_pending, vcpu->kvm))
|
||||
if (KVM_BUG_ON(vcpu->arch.nested_run_pending, vcpu->kvm))
|
||||
return -EIO;
|
||||
|
||||
if (is_guest_mode(vcpu)) {
|
||||
@@ -7730,11 +7730,11 @@ fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
|
||||
* Track VMLAUNCH/VMRESUME that have made past guest state
|
||||
* checking.
|
||||
*/
|
||||
if (vmx->nested.nested_run_pending &&
|
||||
if (vcpu->arch.nested_run_pending &&
|
||||
!vmx_get_exit_reason(vcpu).failed_vmentry)
|
||||
++vcpu->stat.nested_run;
|
||||
|
||||
vmx->nested.nested_run_pending = 0;
|
||||
vcpu->arch.nested_run_pending = 0;
|
||||
}
|
||||
|
||||
if (unlikely(vmx->fail))
|
||||
@@ -8491,7 +8491,7 @@ void vmx_setup_mce(struct kvm_vcpu *vcpu)
|
||||
int vmx_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
|
||||
{
|
||||
/* we need a nested vmexit to enter SMM, postpone if run is pending */
|
||||
if (to_vmx(vcpu)->nested.nested_run_pending)
|
||||
if (vcpu->arch.nested_run_pending)
|
||||
return -EBUSY;
|
||||
return !is_smm(vcpu);
|
||||
}
|
||||
@@ -8536,7 +8536,7 @@ int vmx_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
|
||||
if (ret != NVMX_VMENTRY_SUCCESS)
|
||||
return 1;
|
||||
|
||||
vmx->nested.nested_run_pending = 1;
|
||||
vcpu->arch.nested_run_pending = KVM_NESTED_RUN_PENDING;
|
||||
vmx->nested.smm.guest_mode = false;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -138,9 +138,6 @@ struct nested_vmx {
|
||||
*/
|
||||
bool enlightened_vmcs_enabled;
|
||||
|
||||
/* L2 must run next, and mustn't decide to exit to L1. */
|
||||
bool nested_run_pending;
|
||||
|
||||
/* Pending MTF VM-exit into L1. */
|
||||
bool mtf_pending;
|
||||
|
||||
|
||||
+55
-23
@@ -351,6 +351,9 @@ static const u32 msrs_to_save_base[] = {
|
||||
MSR_IA32_U_CET, MSR_IA32_S_CET,
|
||||
MSR_IA32_PL0_SSP, MSR_IA32_PL1_SSP, MSR_IA32_PL2_SSP,
|
||||
MSR_IA32_PL3_SSP, MSR_IA32_INT_SSP_TAB,
|
||||
MSR_IA32_DEBUGCTLMSR,
|
||||
MSR_IA32_LASTBRANCHFROMIP, MSR_IA32_LASTBRANCHTOIP,
|
||||
MSR_IA32_LASTINTFROMIP, MSR_IA32_LASTINTTOIP,
|
||||
};
|
||||
|
||||
static const u32 msrs_to_save_pmu[] = {
|
||||
@@ -864,9 +867,6 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, unsigned int nr,
|
||||
vcpu->arch.exception.error_code = error_code;
|
||||
vcpu->arch.exception.has_payload = has_payload;
|
||||
vcpu->arch.exception.payload = payload;
|
||||
if (!is_guest_mode(vcpu))
|
||||
kvm_deliver_exception_payload(vcpu,
|
||||
&vcpu->arch.exception);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5531,18 +5531,8 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_events *events)
|
||||
static struct kvm_queued_exception *kvm_get_exception_to_save(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_queued_exception *ex;
|
||||
|
||||
process_nmi(vcpu);
|
||||
|
||||
#ifdef CONFIG_KVM_SMM
|
||||
if (kvm_check_request(KVM_REQ_SMI, vcpu))
|
||||
process_smi(vcpu);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* KVM's ABI only allows for one exception to be migrated. Luckily,
|
||||
* the only time there can be two queued exceptions is if there's a
|
||||
@@ -5553,21 +5543,46 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
|
||||
if (vcpu->arch.exception_vmexit.pending &&
|
||||
!vcpu->arch.exception.pending &&
|
||||
!vcpu->arch.exception.injected)
|
||||
ex = &vcpu->arch.exception_vmexit;
|
||||
else
|
||||
ex = &vcpu->arch.exception;
|
||||
return &vcpu->arch.exception_vmexit;
|
||||
|
||||
return &vcpu->arch.exception;
|
||||
}
|
||||
|
||||
static void kvm_handle_exception_payload_quirk(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_queued_exception *ex = kvm_get_exception_to_save(vcpu);
|
||||
|
||||
/*
|
||||
* In guest mode, payload delivery should be deferred if the exception
|
||||
* will be intercepted by L1, e.g. KVM should not modifying CR2 if L1
|
||||
* intercepts #PF, ditto for DR6 and #DBs. If the per-VM capability,
|
||||
* KVM_CAP_EXCEPTION_PAYLOAD, is not set, userspace may or may not
|
||||
* propagate the payload and so it cannot be safely deferred. Deliver
|
||||
* the payload if the capability hasn't been requested.
|
||||
* If KVM_CAP_EXCEPTION_PAYLOAD is disabled, then (prematurely) deliver
|
||||
* the pending exception payload when userspace saves *any* vCPU state
|
||||
* that interacts with exception payloads to avoid breaking userspace.
|
||||
*
|
||||
* Architecturally, KVM must not deliver an exception payload until the
|
||||
* exception is actually injected, e.g. to avoid losing pending #DB
|
||||
* information (which VMX tracks in the VMCS), and to avoid clobbering
|
||||
* state if the exception is never injected for whatever reason. But
|
||||
* if KVM_CAP_EXCEPTION_PAYLOAD isn't enabled, then userspace may or
|
||||
* may not propagate the payload across save+restore, and so KVM can't
|
||||
* safely defer delivery of the payload.
|
||||
*/
|
||||
if (!vcpu->kvm->arch.exception_payload_enabled &&
|
||||
ex->pending && ex->has_payload)
|
||||
kvm_deliver_exception_payload(vcpu, ex);
|
||||
}
|
||||
|
||||
static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_events *events)
|
||||
{
|
||||
struct kvm_queued_exception *ex = kvm_get_exception_to_save(vcpu);
|
||||
|
||||
process_nmi(vcpu);
|
||||
|
||||
#ifdef CONFIG_KVM_SMM
|
||||
if (kvm_check_request(KVM_REQ_SMI, vcpu))
|
||||
process_smi(vcpu);
|
||||
#endif
|
||||
|
||||
kvm_handle_exception_payload_quirk(vcpu);
|
||||
|
||||
memset(events, 0, sizeof(*events));
|
||||
|
||||
@@ -5746,6 +5761,8 @@ static int kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
|
||||
vcpu->arch.guest_state_protected)
|
||||
return -EINVAL;
|
||||
|
||||
kvm_handle_exception_payload_quirk(vcpu);
|
||||
|
||||
memset(dbgregs, 0, sizeof(*dbgregs));
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(vcpu->arch.db) != ARRAY_SIZE(dbgregs->db));
|
||||
@@ -8897,6 +8914,11 @@ static bool emulator_is_canonical_addr(struct x86_emulate_ctxt *ctxt,
|
||||
return !is_noncanonical_address(addr, emul_to_vcpu(ctxt), flags);
|
||||
}
|
||||
|
||||
static bool emulator_page_address_valid(struct x86_emulate_ctxt *ctxt, gpa_t gpa)
|
||||
{
|
||||
return page_address_valid(emul_to_vcpu(ctxt), gpa);
|
||||
}
|
||||
|
||||
static const struct x86_emulate_ops emulate_ops = {
|
||||
.vm_bugged = emulator_vm_bugged,
|
||||
.read_gpr = emulator_read_gpr,
|
||||
@@ -8944,6 +8966,7 @@ static const struct x86_emulate_ops emulate_ops = {
|
||||
.set_xcr = emulator_set_xcr,
|
||||
.get_untagged_addr = emulator_get_untagged_addr,
|
||||
.is_canonical_addr = emulator_is_canonical_addr,
|
||||
.page_address_valid = emulator_page_address_valid,
|
||||
};
|
||||
|
||||
static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask)
|
||||
@@ -11916,6 +11939,13 @@ static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
|
||||
|
||||
static int kvm_x86_vcpu_pre_run(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* Userspace may have modified vCPU state, mark nested_run_pending as
|
||||
* "untrusted" to avoid triggering false-positive WARNs.
|
||||
*/
|
||||
if (vcpu->arch.nested_run_pending == KVM_NESTED_RUN_PENDING)
|
||||
vcpu->arch.nested_run_pending = KVM_NESTED_RUN_PENDING_UNTRUSTED;
|
||||
|
||||
/*
|
||||
* SIPI_RECEIVED is obsolete; KVM leaves the vCPU in Wait-For-SIPI and
|
||||
* tracks the pending SIPI separately. SIPI_RECEIVED is still accepted
|
||||
@@ -12156,6 +12186,8 @@ static void __get_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
|
||||
if (vcpu->arch.guest_state_protected)
|
||||
goto skip_protected_regs;
|
||||
|
||||
kvm_handle_exception_payload_quirk(vcpu);
|
||||
|
||||
kvm_get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
|
||||
kvm_get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
|
||||
kvm_get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
|
||||
|
||||
@@ -188,6 +188,16 @@ static inline bool kvm_can_set_cpuid_and_feature_msrs(struct kvm_vcpu *vcpu)
|
||||
return vcpu->arch.last_vmentry_cpu == -1 && !is_guest_mode(vcpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* WARN if a nested VM-Enter is pending completion, and userspace hasn't gained
|
||||
* control since the nested VM-Enter was initiated (in which case, userspace
|
||||
* may have modified vCPU state to induce an architecturally invalid VM-Exit).
|
||||
*/
|
||||
static inline void kvm_warn_on_nested_run_pending(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
WARN_ON_ONCE(vcpu->arch.nested_run_pending == KVM_NESTED_RUN_PENDING);
|
||||
}
|
||||
|
||||
static inline void kvm_set_mp_state(struct kvm_vcpu *vcpu, int mp_state)
|
||||
{
|
||||
vcpu->arch.mp_state = mp_state;
|
||||
|
||||
@@ -111,8 +111,11 @@ TEST_GEN_PROGS_x86 += x86/state_test
|
||||
TEST_GEN_PROGS_x86 += x86/vmx_preemption_timer_test
|
||||
TEST_GEN_PROGS_x86 += x86/svm_vmcall_test
|
||||
TEST_GEN_PROGS_x86 += x86/svm_int_ctl_test
|
||||
TEST_GEN_PROGS_x86 += x86/svm_nested_clear_efer_svme
|
||||
TEST_GEN_PROGS_x86 += x86/svm_nested_shutdown_test
|
||||
TEST_GEN_PROGS_x86 += x86/svm_nested_soft_inject_test
|
||||
TEST_GEN_PROGS_x86 += x86/svm_nested_vmcb12_gpa
|
||||
TEST_GEN_PROGS_x86 += x86/svm_lbr_nested_state
|
||||
TEST_GEN_PROGS_x86 += x86/tsc_scaling_sync
|
||||
TEST_GEN_PROGS_x86 += x86/sync_regs_test
|
||||
TEST_GEN_PROGS_x86 += x86/ucna_injection_test
|
||||
|
||||
@@ -1390,6 +1390,11 @@ static inline bool kvm_is_ignore_msrs(void)
|
||||
return get_kvm_param_bool("ignore_msrs");
|
||||
}
|
||||
|
||||
static inline bool kvm_is_lbrv_enabled(void)
|
||||
{
|
||||
return !!get_kvm_amd_param_integer("lbrv");
|
||||
}
|
||||
|
||||
uint64_t *vm_get_pte(struct kvm_vm *vm, uint64_t vaddr);
|
||||
|
||||
uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2,
|
||||
|
||||
@@ -97,13 +97,13 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
|
||||
u64 exit_info_2;
|
||||
u32 exit_int_info;
|
||||
u32 exit_int_info_err;
|
||||
u64 nested_ctl;
|
||||
u64 misc_ctl;
|
||||
u64 avic_vapic_bar;
|
||||
u8 reserved_4[8];
|
||||
u32 event_inj;
|
||||
u32 event_inj_err;
|
||||
u64 nested_cr3;
|
||||
u64 virt_ext;
|
||||
u64 misc_ctl2;
|
||||
u32 clean;
|
||||
u32 reserved_5;
|
||||
u64 next_rip;
|
||||
@@ -155,9 +155,6 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
|
||||
#define AVIC_ENABLE_SHIFT 31
|
||||
#define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT)
|
||||
|
||||
#define LBR_CTL_ENABLE_MASK BIT_ULL(0)
|
||||
#define VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK BIT_ULL(1)
|
||||
|
||||
#define SVM_INTERRUPT_SHADOW_MASK 1
|
||||
|
||||
#define SVM_IOIO_STR_SHIFT 2
|
||||
@@ -175,8 +172,11 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
|
||||
#define SVM_VM_CR_SVM_LOCK_MASK 0x0008ULL
|
||||
#define SVM_VM_CR_SVM_DIS_MASK 0x0010ULL
|
||||
|
||||
#define SVM_NESTED_CTL_NP_ENABLE BIT(0)
|
||||
#define SVM_NESTED_CTL_SEV_ENABLE BIT(1)
|
||||
#define SVM_MISC_ENABLE_NP BIT(0)
|
||||
#define SVM_MISC_ENABLE_SEV BIT(1)
|
||||
|
||||
#define SVM_MISC2_ENABLE_V_LBR BIT_ULL(0)
|
||||
#define SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE BIT_ULL(1)
|
||||
|
||||
struct __attribute__ ((__packed__)) vmcb_seg {
|
||||
u16 selector;
|
||||
|
||||
@@ -126,7 +126,7 @@ void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_r
|
||||
guest_regs.rdi = (u64)svm;
|
||||
|
||||
if (svm->ncr3_gpa) {
|
||||
ctrl->nested_ctl |= SVM_NESTED_CTL_NP_ENABLE;
|
||||
ctrl->misc_ctl |= SVM_MISC_ENABLE_NP;
|
||||
ctrl->nested_cr3 = svm->ncr3_gpa;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,8 +79,8 @@ static void l1_guest_code(struct svm_test_data *svm)
|
||||
svm->vmcb->control.intercept |= (BIT_ULL(INTERCEPT_VMSAVE) |
|
||||
BIT_ULL(INTERCEPT_VMLOAD));
|
||||
|
||||
/* ..VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK cleared.. */
|
||||
svm->vmcb->control.virt_ext &= ~VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
|
||||
/* ..SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE cleared.. */
|
||||
svm->vmcb->control.misc_ctl2 &= ~SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE;
|
||||
|
||||
svm->vmcb->save.rip = (u64)l2_guest_code_vmsave;
|
||||
run_guest(svm->vmcb, svm->vmcb_gpa);
|
||||
@@ -90,8 +90,8 @@ static void l1_guest_code(struct svm_test_data *svm)
|
||||
run_guest(svm->vmcb, svm->vmcb_gpa);
|
||||
GUEST_ASSERT_EQ(svm->vmcb->control.exit_code, SVM_EXIT_VMLOAD);
|
||||
|
||||
/* ..and VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK set */
|
||||
svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
|
||||
/* ..and SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE set */
|
||||
svm->vmcb->control.misc_ctl2 |= SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE;
|
||||
|
||||
svm->vmcb->save.rip = (u64)l2_guest_code_vmsave;
|
||||
run_guest(svm->vmcb, svm->vmcb_gpa);
|
||||
@@ -106,20 +106,20 @@ static void l1_guest_code(struct svm_test_data *svm)
|
||||
BIT_ULL(INTERCEPT_VMLOAD));
|
||||
|
||||
/*
|
||||
* Without VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK, the GPA will be
|
||||
* Without SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE, the GPA will be
|
||||
* interpreted as an L1 GPA, so VMCB0 should be used.
|
||||
*/
|
||||
svm->vmcb->save.rip = (u64)l2_guest_code_vmcb0;
|
||||
svm->vmcb->control.virt_ext &= ~VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
|
||||
svm->vmcb->control.misc_ctl2 &= ~SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE;
|
||||
run_guest(svm->vmcb, svm->vmcb_gpa);
|
||||
GUEST_ASSERT_EQ(svm->vmcb->control.exit_code, SVM_EXIT_VMMCALL);
|
||||
|
||||
/*
|
||||
* With VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK, the GPA will be interpeted as
|
||||
* With SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE, the GPA will be interpeted as
|
||||
* an L2 GPA, and translated through the NPT to VMCB1.
|
||||
*/
|
||||
svm->vmcb->save.rip = (u64)l2_guest_code_vmcb1;
|
||||
svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
|
||||
svm->vmcb->control.misc_ctl2 |= SVM_MISC2_ENABLE_V_VMLOAD_VMSAVE;
|
||||
run_guest(svm->vmcb, svm->vmcb_gpa);
|
||||
GUEST_ASSERT_EQ(svm->vmcb->control.exit_code, SVM_EXIT_VMMCALL);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user