Commit ea9bd29a authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvm-x86-fixes-6.14-rcN.2' of https://github.com/kvm-x86/linux into HEAD

KVM x86 fixes for 6.14-rcN #2

 - Set RFLAGS.IF in C code on SVM to get VMRUN out of the STI shadow.

 - Ensure DEBUGCTL is context switched on AMD to avoid running the guest with
   the host's value, which can lead to unexpected bus lock #DBs.

 - Suppress DEBUGCTL.BTF on AMD (to match Intel), as KVM doesn't properly
   emulate BTF.  KVM's lack of context switching has meant BTF has always been
   broken to some extent.

 - Always save DR masks for SNP vCPUs if DebugSwap is *supported*, as the guest
   can enable DebugSwap without KVM's knowledge.

 - Fix a bug in mmu_stress_tests where a vCPU could finish the "writes to RO
   memory" phase without actually generating a write-protection fault.

 - Fix a printf() goof in the SEV smoke test that causes build failures with
   -Werror.

 - Explicitly zero EAX and EBX in CPUID.0x8000_0022 output when PERFMON_V2
   isn't supported by KVM.
parents 1cdad678 f9dc8fb3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -780,6 +780,7 @@ struct kvm_vcpu_arch {
	u32 pkru;
	u32 hflags;
	u64 efer;
	u64 host_debugctl;
	u64 apic_base;
	struct kvm_lapic *apic;    /* kernel irqchip context */
	bool load_eoi_exitmap_pending;
+1 −1
Original line number Diff line number Diff line
@@ -1763,7 +1763,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)

		entry->ecx = entry->edx = 0;
		if (!enable_pmu || !kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2)) {
			entry->eax = entry->ebx;
			entry->eax = entry->ebx = 0;
			break;
		}

+17 −7
Original line number Diff line number Diff line
@@ -4590,6 +4590,8 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm)

void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa)
{
	struct kvm *kvm = svm->vcpu.kvm;

	/*
	 * All host state for SEV-ES guests is categorized into three swap types
	 * based on how it is handled by hardware during a world switch:
@@ -4613,14 +4615,22 @@ void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_are

	/*
	 * If DebugSwap is enabled, debug registers are loaded but NOT saved by
	 * the CPU (Type-B). If DebugSwap is disabled/unsupported, the CPU both
	 * saves and loads debug registers (Type-A).
	 * the CPU (Type-B). If DebugSwap is disabled/unsupported, the CPU does
	 * not save or load debug registers.  Sadly, KVM can't prevent SNP
	 * guests from lying about DebugSwap on secondary vCPUs, i.e. the
	 * SEV_FEATURES provided at "AP Create" isn't guaranteed to match what
	 * the guest has actually enabled (or not!) in the VMSA.
	 *
	 * If DebugSwap is *possible*, save the masks so that they're restored
	 * if the guest enables DebugSwap.  But for the DRs themselves, do NOT
	 * rely on the CPU to restore the host values; KVM will restore them as
	 * needed in common code, via hw_breakpoint_restore().  Note, KVM does
	 * NOT support virtualizing Breakpoint Extensions, i.e. the mask MSRs
	 * don't need to be restored per se, KVM just needs to ensure they are
	 * loaded with the correct values *if* the CPU writes the MSRs.
	 */
	if (sev_vcpu_has_debug_swap(svm)) {
		hostsa->dr0 = native_get_debugreg(0);
		hostsa->dr1 = native_get_debugreg(1);
		hostsa->dr2 = native_get_debugreg(2);
		hostsa->dr3 = native_get_debugreg(3);
	if (sev_vcpu_has_debug_swap(svm) ||
	    (sev_snp_guest(kvm) && cpu_feature_enabled(X86_FEATURE_DEBUG_SWAP))) {
		hostsa->dr0_addr_mask = amd_get_dr_addr_mask(0);
		hostsa->dr1_addr_mask = amd_get_dr_addr_mask(1);
		hostsa->dr2_addr_mask = amd_get_dr_addr_mask(2);
+49 −0
Original line number Diff line number Diff line
@@ -3165,6 +3165,27 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
			kvm_pr_unimpl_wrmsr(vcpu, ecx, data);
			break;
		}

		/*
		 * AMD changed the architectural behavior of bits 5:2.  On CPUs
		 * without BusLockTrap, bits 5:2 control "external pins", but
		 * on CPUs that support BusLockDetect, bit 2 enables BusLockTrap
		 * and bits 5:3 are reserved-to-zero.  Sadly, old KVM allowed
		 * the guest to set bits 5:2 despite not actually virtualizing
		 * Performance-Monitoring/Breakpoint external pins.  Drop bits
		 * 5:2 for backwards compatibility.
		 */
		data &= ~GENMASK(5, 2);

		/*
		 * Suppress BTF as KVM doesn't virtualize BTF, but there's no
		 * way to communicate lack of support to the guest.
		 */
		if (data & DEBUGCTLMSR_BTF) {
			kvm_pr_unimpl_wrmsr(vcpu, MSR_IA32_DEBUGCTLMSR, data);
			data &= ~DEBUGCTLMSR_BTF;
		}

		if (data & DEBUGCTL_RESERVED_BITS)
			return 1;

@@ -4189,6 +4210,18 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, bool spec_ctrl_in

	guest_state_enter_irqoff();

	/*
	 * Set RFLAGS.IF prior to VMRUN, as the host's RFLAGS.IF at the time of
	 * VMRUN controls whether or not physical IRQs are masked (KVM always
	 * runs with V_INTR_MASKING_MASK).  Toggle RFLAGS.IF here to avoid the
	 * temptation to do STI+VMRUN+CLI, as AMD CPUs bleed the STI shadow
	 * into guest state if delivery of an event during VMRUN triggers a
	 * #VMEXIT, and the guest_state transitions already tell lockdep that
	 * IRQs are being enabled/disabled.  Note!  GIF=0 for the entirety of
	 * this path, so IRQs aren't actually unmasked while running host code.
	 */
	raw_local_irq_enable();

	amd_clear_divider();

	if (sev_es_guest(vcpu->kvm))
@@ -4197,6 +4230,8 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, bool spec_ctrl_in
	else
		__svm_vcpu_run(svm, spec_ctrl_intercepted);

	raw_local_irq_disable();

	guest_state_exit_irqoff();
}

@@ -4253,6 +4288,16 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu,
	clgi();
	kvm_load_guest_xsave_state(vcpu);

	/*
	 * Hardware only context switches DEBUGCTL if LBR virtualization is
	 * enabled.  Manually load DEBUGCTL if necessary (and restore it after
	 * VM-Exit), as running with the host's DEBUGCTL can negatively affect
	 * guest state and can even be fatal, e.g. due to Bus Lock Detect.
	 */
	if (!(svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK) &&
	    vcpu->arch.host_debugctl != svm->vmcb->save.dbgctl)
		update_debugctlmsr(svm->vmcb->save.dbgctl);

	kvm_wait_lapic_expire(vcpu);

	/*
@@ -4280,6 +4325,10 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu,
	if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
		kvm_before_interrupt(vcpu, KVM_HANDLING_NMI);

	if (!(svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK) &&
	    vcpu->arch.host_debugctl != svm->vmcb->save.dbgctl)
		update_debugctlmsr(vcpu->arch.host_debugctl);

	kvm_load_host_xsave_state(vcpu);
	stgi();

+1 −1
Original line number Diff line number Diff line
@@ -584,7 +584,7 @@ static inline bool is_vnmi_enabled(struct vcpu_svm *svm)
/* svm.c */
#define MSR_INVALID				0xffffffffU

#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
#define DEBUGCTL_RESERVED_BITS (~DEBUGCTLMSR_LBR)

extern bool dump_invalid_vmcb;

Loading