Commit 484612f1 authored by Isaku Yamahata's avatar Isaku Yamahata Committed by Paolo Bonzini
Browse files

KVM: x86: Add a switch_db_regs flag to handle TDX's auto-switched behavior



Add a flag KVM_DEBUGREG_AUTO_SWITCH to skip saving/restoring guest
DRs.

TDX-SEAM unconditionally saves/restores guest DRs on TD exit/enter,
and resets DRs to architectural INIT state on TD exit.  Use the new
flag KVM_DEBUGREG_AUTO_SWITCH to indicate that KVM doesn't need to
save/restore guest DRs.  KVM still needs to restore host DRs after TD
exit if there are active breakpoints in the host, which is covered by
the existing code.

MOV-DR exiting is always cleared for TDX guests, so the handler for DR
access is never called, and KVM_DEBUGREG_WONT_EXIT is never set.  Add
a warning if both KVM_DEBUGREG_WONT_EXIT and KVM_DEBUGREG_AUTO_SWITCH
are set.

Opportunistically convert the KVM_DEBUGREG_* definitions to use BIT().

Reported-by: default avatarXiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: default avatarSean Christopherson <sean.j.christopherson@intel.com>
Co-developed-by: default avatarChao Gao <chao.gao@intel.com>
Signed-off-by: default avatarChao Gao <chao.gao@intel.com>
Signed-off-by: default avatarIsaku Yamahata <isaku.yamahata@intel.com>
[binbin: rework changelog]
Signed-off-by: default avatarBinbin Wu <binbin.wu@linux.intel.com>
Message-ID: <20241210004946.3718496-2-binbin.wu@linux.intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Message-ID: <20250129095902.16391-13-adrian.hunter@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 8af09903
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -606,8 +606,15 @@ struct kvm_pmu {
struct kvm_pmu_ops;

enum {
	KVM_DEBUGREG_BP_ENABLED = 1,
	KVM_DEBUGREG_WONT_EXIT = 2,
	KVM_DEBUGREG_BP_ENABLED		= BIT(0),
	KVM_DEBUGREG_WONT_EXIT		= BIT(1),
	/*
	 * Guest debug registers (DR0-3, DR6 and DR7) are saved/restored by
	 * hardware on exit from or enter to guest. KVM needn't switch them.
	 * DR0-3, DR6 and DR7 are set to their architectural INIT value on VM
	 * exit, host values need to be restored.
	 */
	KVM_DEBUGREG_AUTO_SWITCH	= BIT(2),
};

struct kvm_mtrr {
+1 −0
Original line number Diff line number Diff line
@@ -630,6 +630,7 @@ int tdx_vcpu_create(struct kvm_vcpu *vcpu)

	vcpu->arch.efer = EFER_SCE | EFER_LME | EFER_LMA | EFER_NX;

	vcpu->arch.switch_db_regs = KVM_DEBUGREG_AUTO_SWITCH;
	vcpu->arch.cr0_guest_owned_bits = -1ul;
	vcpu->arch.cr4_guest_owned_bits = -1ul;

+3 −1
Original line number Diff line number Diff line
@@ -10985,7 +10985,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
	if (vcpu->arch.guest_fpu.xfd_err)
		wrmsrl(MSR_IA32_XFD_ERR, vcpu->arch.guest_fpu.xfd_err);

	if (unlikely(vcpu->arch.switch_db_regs)) {
	if (unlikely(vcpu->arch.switch_db_regs &&
		     !(vcpu->arch.switch_db_regs & KVM_DEBUGREG_AUTO_SWITCH))) {
		set_debugreg(0, 7);
		set_debugreg(vcpu->arch.eff_db[0], 0);
		set_debugreg(vcpu->arch.eff_db[1], 1);
@@ -11037,6 +11038,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
	 */
	if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) {
		WARN_ON(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP);
		WARN_ON(vcpu->arch.switch_db_regs & KVM_DEBUGREG_AUTO_SWITCH);
		kvm_x86_call(sync_dirty_debug_regs)(vcpu);
		kvm_update_dr0123(vcpu);
		kvm_update_dr7(vcpu);