kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2/6] KVM: x86: Optimize debug register switching
  2009-09-04 12:51 [PATCH 0/6] Debug register emulation fixes and optimizations Jan Kiszka
@ 2009-09-04 12:51 ` Jan Kiszka
  2009-09-06  8:10   ` Avi Kivity
  2009-09-04 12:51 ` [PATCH 1/6] KGDB: Add kgdb_in_use Jan Kiszka
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 9+ messages in thread
From: Jan Kiszka @ 2009-09-04 12:51 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Jan Kiszka

Based on Avi's suggestion: Do not save the host debug registers on guest
entry as they are already present in the thread state. Moreover, only
restore them if the current host thread is being debugged. But as KGDB
accesses the debug register directly, we have to fall back to existing
pattern in that case.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

 arch/x86/kvm/x86.c |   48 +++++++++++++++++++++++++++++++++---------------
 1 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 891234b..036a2c5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -37,6 +37,7 @@
 #include <linux/iommu.h>
 #include <linux/intel-iommu.h>
 #include <linux/cpufreq.h>
+#include <linux/kgdb.h>
 #include <trace/events/kvm.h>
 #undef TRACE_INCLUDE_FILE
 #define CREATE_TRACE_POINTS
@@ -3627,14 +3628,21 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
 	kvm_guest_enter();
 
-	get_debugreg(vcpu->arch.host_dr6, 6);
-	get_debugreg(vcpu->arch.host_dr7, 7);
+	/*
+	 * kgdb accesses the debug registers directly, so we have to save them
+	 * and restore those values on return from the guest.
+	 */
+	if (unlikely(kgdb_in_use())) {
+		if (unlikely(vcpu->arch.switch_db_regs)) {
+			get_debugreg(vcpu->arch.host_db[0], 0);
+			get_debugreg(vcpu->arch.host_db[1], 1);
+			get_debugreg(vcpu->arch.host_db[2], 2);
+			get_debugreg(vcpu->arch.host_db[3], 3);
+		}
+		get_debugreg(vcpu->arch.host_dr6, 6);
+		get_debugreg(vcpu->arch.host_dr7, 7);
+	}
 	if (unlikely(vcpu->arch.switch_db_regs)) {
-		get_debugreg(vcpu->arch.host_db[0], 0);
-		get_debugreg(vcpu->arch.host_db[1], 1);
-		get_debugreg(vcpu->arch.host_db[2], 2);
-		get_debugreg(vcpu->arch.host_db[3], 3);
-
 		set_debugreg(0, 7);
 		set_debugreg(vcpu->arch.eff_db[0], 0);
 		set_debugreg(vcpu->arch.eff_db[1], 1);
@@ -3645,15 +3653,25 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 	trace_kvm_entry(vcpu->vcpu_id);
 	kvm_x86_ops->run(vcpu);
 
-	if (unlikely(vcpu->arch.switch_db_regs)) {
-		set_debugreg(0, 7);
-		set_debugreg(vcpu->arch.host_db[0], 0);
-		set_debugreg(vcpu->arch.host_db[1], 1);
-		set_debugreg(vcpu->arch.host_db[2], 2);
-		set_debugreg(vcpu->arch.host_db[3], 3);
+	if (unlikely(kgdb_in_use())) {
+		if (unlikely(vcpu->arch.switch_db_regs)) {
+			set_debugreg(vcpu->arch.host_db[0], 0);
+			set_debugreg(vcpu->arch.host_db[1], 1);
+			set_debugreg(vcpu->arch.host_db[2], 2);
+			set_debugreg(vcpu->arch.host_db[3], 3);
+		}
+		set_debugreg(vcpu->arch.host_dr6, 6);
+		set_debugreg(vcpu->arch.host_dr7, 7);
+	} else if (unlikely(test_thread_flag(TIF_DEBUG))) {
+		if (unlikely(vcpu->arch.switch_db_regs)) {
+			set_debugreg(current->thread.debugreg0, 0);
+			set_debugreg(current->thread.debugreg1, 1);
+			set_debugreg(current->thread.debugreg2, 2);
+			set_debugreg(current->thread.debugreg3, 3);
+		}
+		set_debugreg(current->thread.debugreg6, 6);
+		set_debugreg(current->thread.debugreg7, 7);
 	}
-	set_debugreg(vcpu->arch.host_dr6, 6);
-	set_debugreg(vcpu->arch.host_dr7, 7);
 
 	set_bit(KVM_REQ_KICK, &vcpu->requests);
 	local_irq_enable();


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 0/6] Debug register emulation fixes and optimizations
@ 2009-09-04 12:51 Jan Kiszka
  2009-09-04 12:51 ` [PATCH 2/6] KVM: x86: Optimize debug register switching Jan Kiszka
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Jan Kiszka @ 2009-09-04 12:51 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm

This series realizes the debug register switch optimization Avi
suggested, but now in a KGDB-safe way. It furthermore cleans up the DR6
optimization as discussed earlier. And it improves the debug register
emulation for both VMX and SVM.

Note that the series applies on top of kvm.git next.

Find this series also at git://git.kiszka.org/linux-kvm.git queues/debugregs

Jan Kiszka (6):
      KGDB: Add kgdb_in_use
      KVM: x86: Optimize debug register switching
      KVM: VMX: Clean up DR6 emulation
      KVM: VMX: Fix emulation of DR4 and DR5
      KVM: SVM: Enable full MOV DR emulation
      KVM: SVM: Trap all debug register accesses

 arch/x86/include/asm/kvm_host.h |    5 +-
 arch/x86/kvm/svm.c              |   86 ++++++++++++++++++++++++--------------
 arch/x86/kvm/vmx.c              |   55 ++++++++++++++----------
 arch/x86/kvm/x86.c              |   67 ++++++++++++++++--------------
 include/linux/kgdb.h            |   17 ++++++++
 5 files changed, 140 insertions(+), 90 deletions(-)



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/6] KVM: VMX: Clean up DR6 emulation
  2009-09-04 12:51 [PATCH 0/6] Debug register emulation fixes and optimizations Jan Kiszka
  2009-09-04 12:51 ` [PATCH 2/6] KVM: x86: Optimize debug register switching Jan Kiszka
  2009-09-04 12:51 ` [PATCH 1/6] KGDB: Add kgdb_in_use Jan Kiszka
@ 2009-09-04 12:51 ` Jan Kiszka
  2009-09-04 12:51 ` [PATCH 5/6] KVM: SVM: Enable full MOV DR emulation Jan Kiszka
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2009-09-04 12:51 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Jan Kiszka

As we trap all debug register accesses, we do not need to switch real
DR6 at all. Clean up update_exception_bitmap at this chance, too.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

 arch/x86/kvm/vmx.c |   22 ++++++----------------
 1 files changed, 6 insertions(+), 16 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index d3213ac..7012680 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -536,18 +536,14 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
 {
 	u32 eb;
 
-	eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR);
+	eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR) |
+	     (1u << DB_VECTOR);
 	if (!vcpu->fpu_active)
 		eb |= 1u << NM_VECTOR;
-	/*
-	 * Unconditionally intercept #DB so we can maintain dr6 without
-	 * reading it every exit.
-	 */
-	eb |= 1u << DB_VECTOR;
-	if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
-		if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
-			eb |= 1u << BP_VECTOR;
-	}
+	if ((vcpu->guest_debug &
+	     (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) ==
+	    (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP))
+		eb |= 1u << BP_VECTOR;
 	if (to_vmx(vcpu)->rmode.vm86_active)
 		eb = ~0;
 	if (enable_ept)
@@ -3627,9 +3623,6 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
 	 */
 	vmcs_writel(HOST_CR0, read_cr0());
 
-	if (vcpu->arch.switch_db_regs)
-		set_debugreg(vcpu->arch.dr6, 6);
-
 	asm(
 		/* Store host registers */
 		"push %%"R"dx; push %%"R"bp;"
@@ -3730,9 +3723,6 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
 				  | (1 << VCPU_EXREG_PDPTR));
 	vcpu->arch.regs_dirty = 0;
 
-	if (vcpu->arch.switch_db_regs)
-		get_debugreg(vcpu->arch.dr6, 6);
-
 	vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
 	if (vmx->rmode.irq.pending)
 		fixup_rmode_irq(vmx);


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 1/6] KGDB: Add kgdb_in_use
  2009-09-04 12:51 [PATCH 0/6] Debug register emulation fixes and optimizations Jan Kiszka
  2009-09-04 12:51 ` [PATCH 2/6] KVM: x86: Optimize debug register switching Jan Kiszka
@ 2009-09-04 12:51 ` Jan Kiszka
  2009-09-04 12:51 ` [PATCH 3/6] KVM: VMX: Clean up DR6 emulation Jan Kiszka
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2009-09-04 12:51 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Jason Wessel, Jan Kiszka

Allow other kernel subsystems to check for kgdb debug sessions. This will
first be used by kvm to switch to conservative debug register saving/restoring
on x86 if kgdb is in use.

CC: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

 include/linux/kgdb.h |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index 6adcc29..aebc768 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -72,6 +72,23 @@ struct uart_port;
  */
 void kgdb_breakpoint(void);
 
+/**
+ *	kgdb_in_use - Check if kgdb is currently in use
+ *
+ *	This function allows other kernel subsystems to check if the kernel
+ *	is currently being debugged via kgdb.  It returns false if not or if
+ *	kgdb support was not built into the kernel.
+ *
+ */
+static inline int kgdb_in_use(void)
+{
+#ifdef CONFIG_KGDB
+	return kgdb_connected;
+#else
+	return 0;
+#endif
+}
+
 extern int kgdb_connected;
 
 extern atomic_t			kgdb_setting_breakpoint;


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 6/6] KVM: SVM: Trap all debug register accesses
  2009-09-04 12:51 [PATCH 0/6] Debug register emulation fixes and optimizations Jan Kiszka
                   ` (3 preceding siblings ...)
  2009-09-04 12:51 ` [PATCH 5/6] KVM: SVM: Enable full MOV DR emulation Jan Kiszka
@ 2009-09-04 12:51 ` Jan Kiszka
  2009-09-04 12:51 ` [PATCH 4/6] KVM: VMX: Fix emulation of DR4 and DR5 Jan Kiszka
  5 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2009-09-04 12:51 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Jan Kiszka

To enable proper debug register emulation under all conditions, trap
access to all DR0..7. This may be optimized later on.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

 arch/x86/kvm/svm.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 4305969..52cbe11 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -551,13 +551,19 @@ static void init_vmcb(struct vcpu_svm *svm)
 	control->intercept_dr_read = 	INTERCEPT_DR0_MASK |
 					INTERCEPT_DR1_MASK |
 					INTERCEPT_DR2_MASK |
-					INTERCEPT_DR3_MASK;
+					INTERCEPT_DR3_MASK |
+					INTERCEPT_DR4_MASK |
+					INTERCEPT_DR5_MASK |
+					INTERCEPT_DR6_MASK |
+					INTERCEPT_DR7_MASK;
 
 	control->intercept_dr_write = 	INTERCEPT_DR0_MASK |
 					INTERCEPT_DR1_MASK |
 					INTERCEPT_DR2_MASK |
 					INTERCEPT_DR3_MASK |
+					INTERCEPT_DR4_MASK |
 					INTERCEPT_DR5_MASK |
+					INTERCEPT_DR6_MASK |
 					INTERCEPT_DR7_MASK;
 
 	control->intercept_exceptions = (1 << PF_VECTOR) |
@@ -2285,11 +2291,17 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
 	[SVM_EXIT_READ_DR1]			= emulate_on_interception,
 	[SVM_EXIT_READ_DR2]			= emulate_on_interception,
 	[SVM_EXIT_READ_DR3]			= emulate_on_interception,
+	[SVM_EXIT_READ_DR4]			= emulate_on_interception,
+	[SVM_EXIT_READ_DR5]			= emulate_on_interception,
+	[SVM_EXIT_READ_DR6]			= emulate_on_interception,
+	[SVM_EXIT_READ_DR7]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_DR0]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_DR1]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_DR2]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_DR3]			= emulate_on_interception,
+	[SVM_EXIT_WRITE_DR4]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_DR5]			= emulate_on_interception,
+	[SVM_EXIT_WRITE_DR6]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_DR7]			= emulate_on_interception,
 	[SVM_EXIT_EXCP_BASE + DB_VECTOR]	= db_interception,
 	[SVM_EXIT_EXCP_BASE + BP_VECTOR]	= bp_interception,


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/6] KVM: SVM: Enable full MOV DR emulation
  2009-09-04 12:51 [PATCH 0/6] Debug register emulation fixes and optimizations Jan Kiszka
                   ` (2 preceding siblings ...)
  2009-09-04 12:51 ` [PATCH 3/6] KVM: VMX: Clean up DR6 emulation Jan Kiszka
@ 2009-09-04 12:51 ` Jan Kiszka
  2009-09-04 12:51 ` [PATCH 6/6] KVM: SVM: Trap all debug register accesses Jan Kiszka
  2009-09-04 12:51 ` [PATCH 4/6] KVM: VMX: Fix emulation of DR4 and DR5 Jan Kiszka
  5 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2009-09-04 12:51 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Jan Kiszka

Enhance MOV DR instruction emulation used by SVM so that it properly
injects faults and handles DR4/5 correctly.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

 arch/x86/include/asm/kvm_host.h |    5 +--
 arch/x86/kvm/svm.c              |   72 ++++++++++++++++++++++-----------------
 arch/x86/kvm/x86.c              |   19 +---------
 3 files changed, 45 insertions(+), 51 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6046e6f..38eef27 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -498,9 +498,8 @@ struct kvm_x86_ops {
 	void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
 	void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
-	unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr);
-	void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value,
-		       int *exception);
+	int (*get_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long *dest);
+	int (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value);
 	void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
 	unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
 	void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 2df9b45..4305969 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1106,76 +1106,86 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)
 	svm->vmcb->control.asid = svm_data->next_asid++;
 }
 
-static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
+static int svm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *dest)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
-	unsigned long val;
 
 	switch (dr) {
 	case 0 ... 3:
-		val = vcpu->arch.db[dr];
+		*dest = vcpu->arch.db[dr];
 		break;
+	case 4:
+		if (vcpu->arch.cr4 & X86_CR4_DE) {
+			kvm_queue_exception(vcpu, UD_VECTOR);
+			return -1;
+		}
+		/* fall through */
 	case 6:
 		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
-			val = vcpu->arch.dr6;
+			*dest = vcpu->arch.dr6;
 		else
-			val = svm->vmcb->save.dr6;
+			*dest = svm->vmcb->save.dr6;
 		break;
+	case 5:
+		if (vcpu->arch.cr4 & X86_CR4_DE) {
+			kvm_queue_exception(vcpu, UD_VECTOR);
+			return -1;
+		}
+		/* fall through */
 	case 7:
 		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
-			val = vcpu->arch.dr7;
+			*dest = vcpu->arch.dr7;
 		else
-			val = svm->vmcb->save.dr7;
+			*dest = svm->vmcb->save.dr7;
 		break;
-	default:
-		val = 0;
 	}
 
-	return val;
+	return 0;
 }
 
-static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
-		       int *exception)
+static int svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 
-	*exception = 0;
-
 	switch (dr) {
 	case 0 ... 3:
 		vcpu->arch.db[dr] = value;
 		if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
 			vcpu->arch.eff_db[dr] = value;
-		return;
-	case 4 ... 5:
-		if (vcpu->arch.cr4 & X86_CR4_DE)
-			*exception = UD_VECTOR;
-		return;
+		break;
+	case 4:
+		if (vcpu->arch.cr4 & X86_CR4_DE) {
+			kvm_queue_exception(vcpu, UD_VECTOR);
+			return -1;
+		}
+		/* fall through */
 	case 6:
 		if (value & 0xffffffff00000000ULL) {
-			*exception = GP_VECTOR;
-			return;
+			kvm_inject_gp(vcpu, 0);
+			return -1;
 		}
 		vcpu->arch.dr6 = (value & DR6_VOLATILE) | DR6_FIXED_1;
-		return;
+		break;
+	case 5:
+		if (vcpu->arch.cr4 & X86_CR4_DE) {
+			kvm_queue_exception(vcpu, UD_VECTOR);
+			return -1;
+		}
+		/* fall through */
 	case 7:
 		if (value & 0xffffffff00000000ULL) {
-			*exception = GP_VECTOR;
-			return;
+			kvm_inject_gp(vcpu, 0);
+			return -1;
 		}
 		vcpu->arch.dr7 = (value & DR7_VOLATILE) | DR7_FIXED_1;
 		if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
 			svm->vmcb->save.dr7 = vcpu->arch.dr7;
 			vcpu->arch.switch_db_regs = (value & DR7_BP_EN_MASK);
 		}
-		return;
-	default:
-		/* FIXME: Possible case? */
-		printk(KERN_DEBUG "%s: unexpected dr %u\n",
-		       __func__, dr);
-		*exception = UD_VECTOR;
-		return;
+		break;
 	}
+
+	return 0;
 }
 
 static int pf_interception(struct vcpu_svm *svm)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 036a2c5..2ca7a1d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2695,29 +2695,14 @@ int emulate_clts(struct kvm_vcpu *vcpu)
 
 int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
 {
-	struct kvm_vcpu *vcpu = ctxt->vcpu;
-
-	switch (dr) {
-	case 0 ... 3:
-		*dest = kvm_x86_ops->get_dr(vcpu, dr);
-		return X86EMUL_CONTINUE;
-	default:
-		pr_unimpl(vcpu, "%s: unexpected dr %u\n", __func__, dr);
-		return X86EMUL_UNHANDLEABLE;
-	}
+	return kvm_x86_ops->get_dr(ctxt->vcpu, dr, dest);
 }
 
 int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
 {
 	unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
-	int exception;
 
-	kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
-	if (exception) {
-		/* FIXME: better handling */
-		return X86EMUL_UNHANDLEABLE;
-	}
-	return X86EMUL_CONTINUE;
+	return kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask);
 }
 
 void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/6] KVM: VMX: Fix emulation of DR4 and DR5
  2009-09-04 12:51 [PATCH 0/6] Debug register emulation fixes and optimizations Jan Kiszka
                   ` (4 preceding siblings ...)
  2009-09-04 12:51 ` [PATCH 6/6] KVM: SVM: Trap all debug register accesses Jan Kiszka
@ 2009-09-04 12:51 ` Jan Kiszka
  5 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2009-09-04 12:51 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, Jan Kiszka

Make sure DR4 and DR5 are aliased to DR6 and DR7, respectively, if
CR4.DE is not set.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

 arch/x86/kvm/vmx.c |   33 ++++++++++++++++++++++++++-------
 1 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 7012680..d34aea5 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2963,14 +2963,24 @@ static int handle_dr(struct kvm_vcpu *vcpu)
 		case 0 ... 3:
 			val = vcpu->arch.db[dr];
 			break;
+		case 4:
+			if (vcpu->arch.cr4 & X86_CR4_DE) {
+				kvm_queue_exception(vcpu, UD_VECTOR);
+				goto skip_instr;
+			}
+			/* fall through */
 		case 6:
 			val = vcpu->arch.dr6;
 			break;
-		case 7:
+		case 5:
+			if (vcpu->arch.cr4 & X86_CR4_DE) {
+				kvm_queue_exception(vcpu, UD_VECTOR);
+				goto skip_instr;
+			}
+			/* fall through */
+		default: /* 7 */
 			val = vcpu->arch.dr7;
 			break;
-		default:
-			val = 0;
 		}
 		kvm_register_write(vcpu, reg, val);
 	} else {
@@ -2981,10 +2991,12 @@ static int handle_dr(struct kvm_vcpu *vcpu)
 			if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
 				vcpu->arch.eff_db[dr] = val;
 			break;
-		case 4 ... 5:
-			if (vcpu->arch.cr4 & X86_CR4_DE)
+		case 4:
+			if (vcpu->arch.cr4 & X86_CR4_DE) {
 				kvm_queue_exception(vcpu, UD_VECTOR);
-			break;
+				break;
+			}
+			/* fall through */
 		case 6:
 			if (val & 0xffffffff00000000ULL) {
 				kvm_queue_exception(vcpu, GP_VECTOR);
@@ -2992,7 +3004,13 @@ static int handle_dr(struct kvm_vcpu *vcpu)
 			}
 			vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
 			break;
-		case 7:
+		case 5:
+			if (vcpu->arch.cr4 & X86_CR4_DE) {
+				kvm_queue_exception(vcpu, UD_VECTOR);
+				break;
+			}
+			/* fall through */
+		default: /* 7 */
 			if (val & 0xffffffff00000000ULL) {
 				kvm_queue_exception(vcpu, GP_VECTOR);
 				break;
@@ -3006,6 +3024,7 @@ static int handle_dr(struct kvm_vcpu *vcpu)
 			break;
 		}
 	}
+skip_instr:
 	skip_emulated_instruction(vcpu);
 	return 1;
 }


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/6] KVM: x86: Optimize debug register switching
  2009-09-04 12:51 ` [PATCH 2/6] KVM: x86: Optimize debug register switching Jan Kiszka
@ 2009-09-06  8:10   ` Avi Kivity
  2009-09-07 13:47     ` Jan Kiszka
  0 siblings, 1 reply; 9+ messages in thread
From: Avi Kivity @ 2009-09-06  8:10 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Marcelo Tosatti, kvm

On 09/04/2009 03:51 PM, Jan Kiszka wrote:
> Based on Avi's suggestion: Do not save the host debug registers on guest
> entry as they are already present in the thread state. Moreover, only
> restore them if the current host thread is being debugged. But as KGDB
> accesses the debug register directly, we have to fall back to existing
> pattern in that case.
>
> Signed-off-by: Jan Kiszka<jan.kiszka@siemens.com>
> ---
>
>   arch/x86/kvm/x86.c |   48 +++++++++++++++++++++++++++++++++---------------
>   1 files changed, 33 insertions(+), 15 deletions(-)
>
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 891234b..036a2c5 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -37,6 +37,7 @@
>   #include<linux/iommu.h>
>   #include<linux/intel-iommu.h>
>   #include<linux/cpufreq.h>
> +#include<linux/kgdb.h>
>   #include<trace/events/kvm.h>
>   #undef TRACE_INCLUDE_FILE
>   #define CREATE_TRACE_POINTS
> @@ -3627,14 +3628,21 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>
>   	kvm_guest_enter();
>
> -	get_debugreg(vcpu->arch.host_dr6, 6);
> -	get_debugreg(vcpu->arch.host_dr7, 7);
> +	/*
> +	 * kgdb accesses the debug registers directly, so we have to save them
> +	 * and restore those values on return from the guest.
> +	 */
> +	if (unlikely(kgdb_in_use())) {
> +		if (unlikely(vcpu->arch.switch_db_regs)) {
> +			get_debugreg(vcpu->arch.host_db[0], 0);
> +			get_debugreg(vcpu->arch.host_db[1], 1);
> +			get_debugreg(vcpu->arch.host_db[2], 2);
> +			get_debugreg(vcpu->arch.host_db[3], 3);
> +		}
> +		get_debugreg(vcpu->arch.host_dr6, 6);
> +		get_debugreg(vcpu->arch.host_dr7, 7);
> +	}
>   	if (unlikely(vcpu->arch.switch_db_regs)) {
> -		get_debugreg(vcpu->arch.host_db[0], 0);
> -		get_debugreg(vcpu->arch.host_db[1], 1);
> -		get_debugreg(vcpu->arch.host_db[2], 2);
> -		get_debugreg(vcpu->arch.host_db[3], 3);
> -
>   		set_debugreg(0, 7);
>   		set_debugreg(vcpu->arch.eff_db[0], 0);
>   		set_debugreg(vcpu->arch.eff_db[1], 1);
> @@ -3645,15 +3653,25 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>   	trace_kvm_entry(vcpu->vcpu_id);
>   	kvm_x86_ops->run(vcpu);
>
> -	if (unlikely(vcpu->arch.switch_db_regs)) {
> -		set_debugreg(0, 7);
> -		set_debugreg(vcpu->arch.host_db[0], 0);
> -		set_debugreg(vcpu->arch.host_db[1], 1);
> -		set_debugreg(vcpu->arch.host_db[2], 2);
> -		set_debugreg(vcpu->arch.host_db[3], 3);
> +	if (unlikely(kgdb_in_use())) {
> +		if (unlikely(vcpu->arch.switch_db_regs)) {
> +			set_debugreg(vcpu->arch.host_db[0], 0);
> +			set_debugreg(vcpu->arch.host_db[1], 1);
> +			set_debugreg(vcpu->arch.host_db[2], 2);
> +			set_debugreg(vcpu->arch.host_db[3], 3);
> +		}
> +		set_debugreg(vcpu->arch.host_dr6, 6);
> +		set_debugreg(vcpu->arch.host_dr7, 7);
> +	} else if (unlikely(test_thread_flag(TIF_DEBUG))) {
> +		if (unlikely(vcpu->arch.switch_db_regs)) {
> +			set_debugreg(current->thread.debugreg0, 0);
> +			set_debugreg(current->thread.debugreg1, 1);
> +			set_debugreg(current->thread.debugreg2, 2);
> +			set_debugreg(current->thread.debugreg3, 3);
> +		}
> +		set_debugreg(current->thread.debugreg6, 6);
> +		set_debugreg(current->thread.debugreg7, 7);
>   	}
> -	set_debugreg(vcpu->arch.host_dr6, 6);
> -	set_debugreg(vcpu->arch.host_dr7, 7);
>
>    

Please, let's have just save/nosave, not different kinds of save/restore.

But really, this looks very hacky.  It's better to have kgdb integrate 
more closely with the kernel debug register support instead of kvm 
juggling between the two.

Something like

   struct debug_registers thread_info::debugregs
   extern struct debug_registers global_debug_registers;

and a function that loads a mix of the debug registers from the 
thread-local and global settings.  The context switch path can call that 
function as well as kvm.

-- 
error compiling committee.c: too many arguments to function


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/6] KVM: x86: Optimize debug register switching
  2009-09-06  8:10   ` Avi Kivity
@ 2009-09-07 13:47     ` Jan Kiszka
  0 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2009-09-07 13:47 UTC (permalink / raw)
  To: Avi Kivity; +Cc: Marcelo Tosatti, kvm@vger.kernel.org

Avi Kivity wrote:
> On 09/04/2009 03:51 PM, Jan Kiszka wrote:
>> Based on Avi's suggestion: Do not save the host debug registers on guest
>> entry as they are already present in the thread state. Moreover, only
>> restore them if the current host thread is being debugged. But as KGDB
>> accesses the debug register directly, we have to fall back to existing
>> pattern in that case.
>>
>> Signed-off-by: Jan Kiszka<jan.kiszka@siemens.com>
>> ---
>>
>>   arch/x86/kvm/x86.c |   48 +++++++++++++++++++++++++++++++++---------------
>>   1 files changed, 33 insertions(+), 15 deletions(-)
>>
>> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
>> index 891234b..036a2c5 100644
>> --- a/arch/x86/kvm/x86.c
>> +++ b/arch/x86/kvm/x86.c
>> @@ -37,6 +37,7 @@
>>   #include<linux/iommu.h>
>>   #include<linux/intel-iommu.h>
>>   #include<linux/cpufreq.h>
>> +#include<linux/kgdb.h>
>>   #include<trace/events/kvm.h>
>>   #undef TRACE_INCLUDE_FILE
>>   #define CREATE_TRACE_POINTS
>> @@ -3627,14 +3628,21 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>>
>>   	kvm_guest_enter();
>>
>> -	get_debugreg(vcpu->arch.host_dr6, 6);
>> -	get_debugreg(vcpu->arch.host_dr7, 7);
>> +	/*
>> +	 * kgdb accesses the debug registers directly, so we have to save them
>> +	 * and restore those values on return from the guest.
>> +	 */
>> +	if (unlikely(kgdb_in_use())) {
>> +		if (unlikely(vcpu->arch.switch_db_regs)) {
>> +			get_debugreg(vcpu->arch.host_db[0], 0);
>> +			get_debugreg(vcpu->arch.host_db[1], 1);
>> +			get_debugreg(vcpu->arch.host_db[2], 2);
>> +			get_debugreg(vcpu->arch.host_db[3], 3);
>> +		}
>> +		get_debugreg(vcpu->arch.host_dr6, 6);
>> +		get_debugreg(vcpu->arch.host_dr7, 7);
>> +	}
>>   	if (unlikely(vcpu->arch.switch_db_regs)) {
>> -		get_debugreg(vcpu->arch.host_db[0], 0);
>> -		get_debugreg(vcpu->arch.host_db[1], 1);
>> -		get_debugreg(vcpu->arch.host_db[2], 2);
>> -		get_debugreg(vcpu->arch.host_db[3], 3);
>> -
>>   		set_debugreg(0, 7);
>>   		set_debugreg(vcpu->arch.eff_db[0], 0);
>>   		set_debugreg(vcpu->arch.eff_db[1], 1);
>> @@ -3645,15 +3653,25 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>>   	trace_kvm_entry(vcpu->vcpu_id);
>>   	kvm_x86_ops->run(vcpu);
>>
>> -	if (unlikely(vcpu->arch.switch_db_regs)) {
>> -		set_debugreg(0, 7);
>> -		set_debugreg(vcpu->arch.host_db[0], 0);
>> -		set_debugreg(vcpu->arch.host_db[1], 1);
>> -		set_debugreg(vcpu->arch.host_db[2], 2);
>> -		set_debugreg(vcpu->arch.host_db[3], 3);
>> +	if (unlikely(kgdb_in_use())) {
>> +		if (unlikely(vcpu->arch.switch_db_regs)) {
>> +			set_debugreg(vcpu->arch.host_db[0], 0);
>> +			set_debugreg(vcpu->arch.host_db[1], 1);
>> +			set_debugreg(vcpu->arch.host_db[2], 2);
>> +			set_debugreg(vcpu->arch.host_db[3], 3);
>> +		}
>> +		set_debugreg(vcpu->arch.host_dr6, 6);
>> +		set_debugreg(vcpu->arch.host_dr7, 7);
>> +	} else if (unlikely(test_thread_flag(TIF_DEBUG))) {
>> +		if (unlikely(vcpu->arch.switch_db_regs)) {
>> +			set_debugreg(current->thread.debugreg0, 0);
>> +			set_debugreg(current->thread.debugreg1, 1);
>> +			set_debugreg(current->thread.debugreg2, 2);
>> +			set_debugreg(current->thread.debugreg3, 3);
>> +		}
>> +		set_debugreg(current->thread.debugreg6, 6);
>> +		set_debugreg(current->thread.debugreg7, 7);
>>   	}
>> -	set_debugreg(vcpu->arch.host_dr6, 6);
>> -	set_debugreg(vcpu->arch.host_dr7, 7);
>>
>>    
> 
> Please, let's have just save/nosave, not different kinds of save/restore.
> 
> But really, this looks very hacky.  It's better to have kgdb integrate 
> more closely with the kernel debug register support instead of kvm 
> juggling between the two.
> 
> Something like
> 
>    struct debug_registers thread_info::debugregs
>    extern struct debug_registers global_debug_registers;
> 
> and a function that loads a mix of the debug registers from the 
> thread-local and global settings.  The context switch path can call that 
> function as well as kvm.

For sure this approach is not nice. /me just wanted to avoid the area of
the "generic hw-breakpoint API". K. Prassad and Frederic Weisbecker
already try to push this abstraction for a fairly long time now.

OK, will go around and poll for status and perspectives of this effort.
Maybe throwing our requirements into the ring also helps accelerating it
a bit.

Jan

-- 
Siemens AG, Corporate Technology, CT SE 2
Corporate Competence Center Embedded Linux

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2009-09-07 13:47 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-04 12:51 [PATCH 0/6] Debug register emulation fixes and optimizations Jan Kiszka
2009-09-04 12:51 ` [PATCH 2/6] KVM: x86: Optimize debug register switching Jan Kiszka
2009-09-06  8:10   ` Avi Kivity
2009-09-07 13:47     ` Jan Kiszka
2009-09-04 12:51 ` [PATCH 1/6] KGDB: Add kgdb_in_use Jan Kiszka
2009-09-04 12:51 ` [PATCH 3/6] KVM: VMX: Clean up DR6 emulation Jan Kiszka
2009-09-04 12:51 ` [PATCH 5/6] KVM: SVM: Enable full MOV DR emulation Jan Kiszka
2009-09-04 12:51 ` [PATCH 6/6] KVM: SVM: Trap all debug register accesses Jan Kiszka
2009-09-04 12:51 ` [PATCH 4/6] KVM: VMX: Fix emulation of DR4 and DR5 Jan Kiszka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).