kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 3/5] KVM: VMX: Ensure interruptibility when single-stepping
  2008-10-06  9:15 [PATCH 0/5] KVM: Fix and improve guest debugging and x86 " Jan Kiszka
@ 2008-10-06  9:15 ` Jan Kiszka
  0 siblings, 0 replies; 18+ messages in thread
From: Jan Kiszka @ 2008-10-06  9:15 UTC (permalink / raw)
  To: kvm; +Cc: Jan Kiszka

[-- Attachment #1: vmx-ensure-interruptibility-on-single-step.patch --]
[-- Type: text/plain, Size: 1413 bytes --]

When single-stepping, we have to ensure that the INT1 can make it
through even if the guest itself is uninterruptible due to MOV SS or
STI. VMENTRY will fail otherwise.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 arch/x86/kvm/vmx.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

Index: b/arch/x86/kvm/vmx.c
===================================================================
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1002,6 +1002,7 @@ static void vmx_cache_reg(struct kvm_vcp
 static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
 {
 	int old_debug = vcpu->guest_debug;
+	u32 interruptibility;
 	unsigned long flags;
 
 	vcpu->guest_debug = dbg->control;
@@ -1009,9 +1010,14 @@ static int set_guest_debug(struct kvm_vc
 		vcpu->guest_debug = 0;
 
 	flags = vmcs_readl(GUEST_RFLAGS);
-	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
 		flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
-	else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
+		/* We must be interruptible when single-stepping */
+		interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+		if (interruptibility & 3)
+			vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
+				     interruptibility & ~3);
+	} else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
 		flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
 	vmcs_writel(GUEST_RFLAGS, flags);
 


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

* [PATCH 0/5] KVM: Improved guest debugging / debug register emulation
@ 2008-11-27 11:43 Jan Kiszka
  2008-11-27 11:43 ` [PATCH 5/5] KVM: x86: Wire-up hardware breakpoints for guest debugging Jan Kiszka
                   ` (4 more replies)
  0 siblings, 5 replies; 18+ messages in thread
From: Jan Kiszka @ 2008-11-27 11:43 UTC (permalink / raw)
  To: kvm; +Cc: Avi Kivity, Hollis Blanchard, Joerg Roedel

This is the kernel part of the guest debugging / debug register
emulation patch series.

Changes since last round:
 - Reinject both soft *and* hard exceptions in vmx_complete_interrupts()

Find the patches also at git://git.kiszka.org/linux-kvm.git gdb-queue

Jan

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

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

* [PATCH 5/5] KVM: x86: Wire-up hardware breakpoints for guest debugging
  2008-11-27 11:43 [PATCH 0/5] KVM: Improved guest debugging / debug register emulation Jan Kiszka
@ 2008-11-27 11:43 ` Jan Kiszka
  2008-11-27 11:43 ` [PATCH 3/5] KVM: VMX: Ensure interruptibility when single-stepping Jan Kiszka
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 18+ messages in thread
From: Jan Kiszka @ 2008-11-27 11:43 UTC (permalink / raw)
  To: kvm; +Cc: Avi Kivity, Hollis Blanchard, Joerg Roedel

Add the remaining bits to make use of debug registers also for guest
debugging, thus enabling the use of hardware breakpoints and
watchpoints.

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

 arch/x86/kvm/svm.c |    5 +++++
 arch/x86/kvm/vmx.c |    5 +++++
 arch/x86/kvm/x86.c |   14 +++++++++++++-
 3 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 5a7dac4..2d17589 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -895,6 +895,11 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
 	} else
 		vcpu->guest_debug = 0;
 
+	if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
+		svm->vmcb->save.dr7 = dbg->arch.debugreg[7];
+	else
+		svm->vmcb->save.dr7 = vcpu->arch.dr7;
+
 	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
 		svm->vmcb->save.rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
 	else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 02db834..648d36e 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1017,6 +1017,11 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
 	if (!(vcpu->guest_debug & KVM_GUESTDBG_ENABLE))
 		vcpu->guest_debug = 0;
 
+	if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
+		vmcs_writel(GUEST_DR7, dbg->arch.debugreg[7]);
+	else
+		vmcs_writel(GUEST_DR7, vcpu->arch.dr7);
+
 	flags = vmcs_readl(GUEST_RFLAGS);
 	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
 		flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 18061b6..0e9f3f4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3854,10 +3854,22 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
 					struct kvm_guest_debug *dbg)
 {
-	int r;
+	int i, r;
 
 	vcpu_load(vcpu);
 
+	if ((dbg->control & (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP)) ==
+	    (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP)) {
+		for (i = 0; i < KVM_NR_DB_REGS; ++i)
+			vcpu->arch.eff_db[i] = dbg->arch.debugreg[i];
+		vcpu->arch.switch_db_regs =
+			(dbg->arch.debugreg[7] & DR7_BP_EN_MASK);
+	} else {
+		for (i = 0; i < KVM_NR_DB_REGS; i++)
+			vcpu->arch.eff_db[i] = vcpu->arch.db[i];
+		vcpu->arch.switch_db_regs = (vcpu->arch.dr7 & DR7_BP_EN_MASK);
+	}
+
 	r = kvm_x86_ops->set_guest_debug(vcpu, dbg);
 
 	if (dbg->control & KVM_GUESTDBG_INJECT_DB)


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

* [PATCH 1/5] VMX: Support for injecting software exceptions
  2008-11-27 11:43 [PATCH 0/5] KVM: Improved guest debugging / debug register emulation Jan Kiszka
  2008-11-27 11:43 ` [PATCH 5/5] KVM: x86: Wire-up hardware breakpoints for guest debugging Jan Kiszka
  2008-11-27 11:43 ` [PATCH 3/5] KVM: VMX: Ensure interruptibility when single-stepping Jan Kiszka
@ 2008-11-27 11:43 ` Jan Kiszka
  2008-11-27 11:43 ` [PATCH 2/5] KVM: New guest debug interface Jan Kiszka
  2008-11-27 11:43 ` [PATCH 4/5] KVM: x86: Virtualize debug registers Jan Kiszka
  4 siblings, 0 replies; 18+ messages in thread
From: Jan Kiszka @ 2008-11-27 11:43 UTC (permalink / raw)
  To: kvm; +Cc: Avi Kivity, Hollis Blanchard, Joerg Roedel

VMX differentiates between processor and software generated exceptions
when injecting them into the guest. Extend vmx_queue_exception
accordingly (and refactor related constants) so that we can use this
service reliably for the new guest debugging framework.

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

 arch/x86/include/asm/vmx.h |    3 ++-
 arch/x86/kvm/vmx.c         |   35 ++++++++++++++++++++---------------
 2 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index d0238e6..32159f0 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -270,8 +270,9 @@ enum vmcs_field {
 
 #define INTR_TYPE_EXT_INTR              (0 << 8) /* external interrupt */
 #define INTR_TYPE_NMI_INTR		(2 << 8) /* NMI */
-#define INTR_TYPE_EXCEPTION             (3 << 8) /* processor exception */
+#define INTR_TYPE_HARD_EXCEPTION	(3 << 8) /* processor exception */
 #define INTR_TYPE_SOFT_INTR             (4 << 8) /* software interrupt */
+#define INTR_TYPE_SOFT_EXCEPTION	(6 << 8) /* software exception */
 
 /* GUEST_INTERRUPTIBILITY_INFO flags. */
 #define GUEST_INTR_STATE_STI		0x00000001
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 7ea4855..da7cc03 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -189,21 +189,21 @@ static inline int is_page_fault(u32 intr_info)
 {
 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
 			     INTR_INFO_VALID_MASK)) ==
-		(INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
+		(INTR_TYPE_HARD_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
 }
 
 static inline int is_no_device(u32 intr_info)
 {
 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
 			     INTR_INFO_VALID_MASK)) ==
-		(INTR_TYPE_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK);
+		(INTR_TYPE_HARD_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK);
 }
 
 static inline int is_invalid_opcode(u32 intr_info)
 {
 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
 			     INTR_INFO_VALID_MASK)) ==
-		(INTR_TYPE_EXCEPTION | UD_VECTOR | INTR_INFO_VALID_MASK);
+		(INTR_TYPE_HARD_EXCEPTION | UD_VECTOR | INTR_INFO_VALID_MASK);
 }
 
 static inline int is_external_interrupt(u32 intr_info)
@@ -747,29 +747,33 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
 				bool has_error_code, u32 error_code)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	u32 intr_info = nr | INTR_INFO_VALID_MASK;
 
-	if (has_error_code)
+	if (has_error_code) {
 		vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+		intr_info |= INTR_INFO_DELIVER_CODE_MASK;
+	}
 
 	if (vcpu->arch.rmode.active) {
 		vmx->rmode.irq.pending = true;
 		vmx->rmode.irq.vector = nr;
 		vmx->rmode.irq.rip = kvm_rip_read(vcpu);
-		if (nr == BP_VECTOR)
+		if (nr == BP_VECTOR || nr == OF_VECTOR)
 			vmx->rmode.irq.rip++;
-		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-			     nr | INTR_TYPE_SOFT_INTR
-			     | (has_error_code ? INTR_INFO_DELIVER_CODE_MASK : 0)
-			     | INTR_INFO_VALID_MASK);
+		intr_info |= INTR_TYPE_SOFT_INTR;
+		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
 		vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
 		kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1);
 		return;
 	}
 
-	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-		     nr | INTR_TYPE_EXCEPTION
-		     | (has_error_code ? INTR_INFO_DELIVER_CODE_MASK : 0)
-		     | INTR_INFO_VALID_MASK);
+	if (nr == BP_VECTOR || nr == OF_VECTOR) {
+		vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
+		intr_info |= INTR_TYPE_SOFT_EXCEPTION;
+	} else
+		intr_info |= INTR_TYPE_HARD_EXCEPTION;
+
+	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
 }
 
 static bool vmx_exception_injected(struct kvm_vcpu *vcpu)
@@ -2649,7 +2653,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	}
 
 	if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) ==
-	    (INTR_TYPE_EXCEPTION | 1)) {
+	    (INTR_TYPE_HARD_EXCEPTION | 1)) {
 		kvm_run->exit_reason = KVM_EXIT_DEBUG;
 		return 0;
 	}
@@ -3255,7 +3259,8 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
 			vmx->vcpu.arch.nmi_injected = false;
 	}
 	kvm_clear_exception_queue(&vmx->vcpu);
-	if (idtv_info_valid && type == INTR_TYPE_EXCEPTION) {
+	if (idtv_info_valid && (type == INTR_TYPE_HARD_EXCEPTION ||
+				type == INTR_TYPE_SOFT_EXCEPTION)) {
 		if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) {
 			error = vmcs_read32(IDT_VECTORING_ERROR_CODE);
 			kvm_queue_exception_e(&vmx->vcpu, vector, error);


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

* [PATCH 4/5] KVM: x86: Virtualize debug registers
  2008-11-27 11:43 [PATCH 0/5] KVM: Improved guest debugging / debug register emulation Jan Kiszka
                   ` (3 preceding siblings ...)
  2008-11-27 11:43 ` [PATCH 2/5] KVM: New guest debug interface Jan Kiszka
@ 2008-11-27 11:43 ` Jan Kiszka
  4 siblings, 0 replies; 18+ messages in thread
From: Jan Kiszka @ 2008-11-27 11:43 UTC (permalink / raw)
  To: kvm; +Cc: Avi Kivity, Hollis Blanchard, Joerg Roedel

So far KVM only had basic x86 debug register support, once introduced to
realize guest debugging that way. The guest itself was not able to use
those registers.

This patch now adds (almost) full support for guest self-debugging via
hardware registers. It refactors the code, moving generic parts out of
SVM (VMX was already cleaned up by the KVM_SET_GUEST_DEBUG patches), and
it ensures that the registers are properly switched between host and
guest.

This patch also prepares debug register usage by the host. The latter
will (once wired-up by the following patch) allow for hardware
breakpoints/watchpoints in guest code. If this is enabled, the guest
will only see faked debug registers without functionality, but with
content reflecting the guest's modifications.

Tested on Intel only, but SVM /should/ work as well, but who knows...

Known limitations: Trapping on tss switch won't work - most probably on
Intel.

Credits also go to Joerg Roedel - I used his once posted debugging
series as platform for this patch.

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

 arch/x86/include/asm/kvm_host.h |   22 +++++++
 arch/x86/include/asm/vmx.h      |    2 -
 arch/x86/kvm/kvm_svm.h          |    6 --
 arch/x86/kvm/svm.c              |  116 ++++++++++++++-------------------------
 arch/x86/kvm/vmx.c              |  114 +++++++++++++++++++++++++++++++++-----
 arch/x86/kvm/x86.c              |   29 ++++++++++
 6 files changed, 193 insertions(+), 96 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7151b08..3a6b9b4 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -134,6 +134,19 @@ enum {
 
 #define KVM_NR_MEM_OBJS 40
 
+#define KVM_NR_DB_REGS	4
+
+#define DR6_BD		(1 << 13)
+#define DR6_BS		(1 << 14)
+#define DR6_FIXED_1	0xffff0ff0
+#define DR6_VOLATILE	0x0000e00f
+
+#define DR7_BP_EN_MASK	0x000000ff
+#define DR7_GE		(1 << 9)
+#define DR7_GD		(1 << 13)
+#define DR7_FIXED_1	0x00000400
+#define DR7_VOLATILE	0xffff23ff
+
 /*
  * We don't want allocation failures within the mmu code, so we preallocate
  * enough memory for a single page fault in a cache.
@@ -329,6 +342,15 @@ struct kvm_vcpu_arch {
 
 	struct mtrr_state_type mtrr_state;
 	u32 pat;
+
+	int switch_db_regs;
+	unsigned long host_db[KVM_NR_DB_REGS];
+	unsigned long host_dr6;
+	unsigned long host_dr7;
+	unsigned long db[KVM_NR_DB_REGS];
+	unsigned long dr6;
+	unsigned long dr7;
+	unsigned long eff_db[KVM_NR_DB_REGS];
 };
 
 struct kvm_mem_alias {
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 32159f0..498f944 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -312,7 +312,7 @@ enum vmcs_field {
 #define DEBUG_REG_ACCESS_TYPE           0x10    /* 4, direction of access */
 #define TYPE_MOV_TO_DR                  (0 << 4)
 #define TYPE_MOV_FROM_DR                (1 << 4)
-#define DEBUG_REG_ACCESS_REG            0xf00   /* 11:8, general purpose reg. */
+#define DEBUG_REG_ACCESS_REG(eq)        (((eq) >> 8) & 0xf) /* 11:8, general purpose reg. */
 
 
 /* segment AR */
diff --git a/arch/x86/kvm/kvm_svm.h b/arch/x86/kvm/kvm_svm.h
index 8e5ee99..680f3cc 100644
--- a/arch/x86/kvm/kvm_svm.h
+++ b/arch/x86/kvm/kvm_svm.h
@@ -18,7 +18,6 @@ static const u32 host_save_user_msrs[] = {
 };
 
 #define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
-#define NUM_DB_REGS 4
 
 struct kvm_vcpu;
 
@@ -29,16 +28,11 @@ struct vcpu_svm {
 	struct svm_cpu_data *svm_data;
 	uint64_t asid_generation;
 
-	unsigned long db_regs[NUM_DB_REGS];
-
 	u64 next_rip;
 
 	u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
 	u64 host_gs_base;
 	unsigned long host_cr2;
-	unsigned long host_db_regs[NUM_DB_REGS];
-	unsigned long host_dr6;
-	unsigned long host_dr7;
 
 	u32 *msrpm;
 };
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index b6cd047..5a7dac4 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -38,9 +38,6 @@ MODULE_LICENSE("GPL");
 #define IOPM_ALLOC_ORDER 2
 #define MSRPM_ALLOC_ORDER 1
 
-#define DR7_GD_MASK (1 << 13)
-#define DR6_BD_MASK (1 << 13)
-
 #define SEG_TYPE_LDT 2
 #define SEG_TYPE_BUSY_TSS16 3
 
@@ -157,32 +154,6 @@ static inline void kvm_write_cr2(unsigned long val)
 	asm volatile ("mov %0, %%cr2" :: "r" (val));
 }
 
-static inline unsigned long read_dr6(void)
-{
-	unsigned long dr6;
-
-	asm volatile ("mov %%dr6, %0" : "=r" (dr6));
-	return dr6;
-}
-
-static inline void write_dr6(unsigned long val)
-{
-	asm volatile ("mov %0, %%dr6" :: "r" (val));
-}
-
-static inline unsigned long read_dr7(void)
-{
-	unsigned long dr7;
-
-	asm volatile ("mov %%dr7, %0" : "=r" (dr7));
-	return dr7;
-}
-
-static inline void write_dr7(unsigned long val)
-{
-	asm volatile ("mov %0, %%dr7" :: "r" (val));
-}
-
 static inline void force_new_asid(struct kvm_vcpu *vcpu)
 {
 	to_svm(vcpu)->asid_generation--;
@@ -644,7 +615,6 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
 	clear_page(svm->vmcb);
 	svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
 	svm->asid_generation = 0;
-	memset(svm->db_regs, 0, sizeof(svm->db_regs));
 	init_vmcb(svm);
 
 	fx_init(&svm->vcpu);
@@ -972,7 +942,29 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)
 
 static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
 {
-	unsigned long val = to_svm(vcpu)->db_regs[dr];
+	struct vcpu_svm *svm = to_svm(vcpu);
+	unsigned long val;
+
+	switch (dr) {
+	case 0 ... 3:
+		val = vcpu->arch.db[dr];
+		break;
+	case 6:
+		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
+			val = vcpu->arch.dr6;
+		else
+			val = svm->vmcb->save.dr6;
+		break;
+	case 7:
+		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
+			val = vcpu->arch.dr7;
+		else
+			val = svm->vmcb->save.dr7;
+		break;
+	default:
+		val = 0;
+	}
+
 	KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler);
 	return val;
 }
@@ -982,33 +974,40 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 
-	*exception = 0;
+	KVMTRACE_2D(DR_WRITE, vcpu, (u32)dr, (u32)value, handler);
 
-	if (svm->vmcb->save.dr7 & DR7_GD_MASK) {
-		svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
-		svm->vmcb->save.dr6 |= DR6_BD_MASK;
-		*exception = DB_VECTOR;
-		return;
-	}
+	*exception = 0;
 
 	switch (dr) {
 	case 0 ... 3:
-		svm->db_regs[dr] = value;
+		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) {
+		if (vcpu->arch.cr4 & X86_CR4_DE)
 			*exception = UD_VECTOR;
+		return;
+	case 6:
+		if (value & 0xffffffff00000000ULL) {
+			*exception = GP_VECTOR;
 			return;
 		}
-	case 7: {
-		if (value & ~((1ULL << 32) - 1)) {
+		vcpu->arch.dr6 = (value & DR6_VOLATILE) | DR6_FIXED_1;
+		return;
+	case 7:
+		if (value & 0xffffffff00000000ULL) {
 			*exception = GP_VECTOR;
 			return;
 		}
-		svm->vmcb->save.dr7 = value;
+		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;
@@ -1709,22 +1708,6 @@ static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
 	return 0;
 }
 
-static void save_db_regs(unsigned long *db_regs)
-{
-	asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0]));
-	asm volatile ("mov %%dr1, %0" : "=r"(db_regs[1]));
-	asm volatile ("mov %%dr2, %0" : "=r"(db_regs[2]));
-	asm volatile ("mov %%dr3, %0" : "=r"(db_regs[3]));
-}
-
-static void load_db_regs(unsigned long *db_regs)
-{
-	asm volatile ("mov %0, %%dr0" : : "r"(db_regs[0]));
-	asm volatile ("mov %0, %%dr1" : : "r"(db_regs[1]));
-	asm volatile ("mov %0, %%dr2" : : "r"(db_regs[2]));
-	asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3]));
-}
-
 static void svm_flush_tlb(struct kvm_vcpu *vcpu)
 {
 	force_new_asid(vcpu);
@@ -1783,19 +1766,11 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	gs_selector = kvm_read_gs();
 	ldt_selector = kvm_read_ldt();
 	svm->host_cr2 = kvm_read_cr2();
-	svm->host_dr6 = read_dr6();
-	svm->host_dr7 = read_dr7();
 	svm->vmcb->save.cr2 = vcpu->arch.cr2;
 	/* required for live migration with NPT */
 	if (npt_enabled)
 		svm->vmcb->save.cr3 = vcpu->arch.cr3;
 
-	if (svm->vmcb->save.dr7 & 0xff) {
-		write_dr7(0);
-		save_db_regs(svm->host_db_regs);
-		load_db_regs(svm->db_regs);
-	}
-
 	clgi();
 
 	local_irq_enable();
@@ -1871,16 +1846,11 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 #endif
 		);
 
-	if ((svm->vmcb->save.dr7 & 0xff))
-		load_db_regs(svm->host_db_regs);
-
 	vcpu->arch.cr2 = svm->vmcb->save.cr2;
 	vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
 	vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
 	vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
 
-	write_dr6(svm->host_dr6);
-	write_dr7(svm->host_dr7);
 	kvm_write_cr2(svm->host_cr2);
 
 	kvm_load_fs(fs_selector);
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 8e83102..02db834 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2316,7 +2316,6 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
 		kvm_rip_write(vcpu, 0);
 	kvm_register_write(vcpu, VCPU_REGS_RSP, 0);
 
-	/* todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0 */
 	vmcs_writel(GUEST_DR7, 0x400);
 
 	vmcs_writel(GUEST_GDTR_BASE, 0);
@@ -2577,7 +2576,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	u32 intr_info, ex_no, error_code;
-	unsigned long cr2, rip;
+	unsigned long cr2, rip, dr6;
 	u32 vect_info;
 	enum emulation_result er;
 
@@ -2637,14 +2636,28 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	}
 
 	ex_no = intr_info & INTR_INFO_VECTOR_MASK;
-	if (ex_no == DB_VECTOR || ex_no == BP_VECTOR) {
+	switch (ex_no) {
+	case DB_VECTOR:
+		dr6 = vmcs_readl(EXIT_QUALIFICATION);
+		if (!(vcpu->guest_debug &
+		      (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
+			vcpu->arch.dr6 = dr6 | DR6_FIXED_1;
+			kvm_queue_exception(vcpu, DB_VECTOR);
+			return 1;
+		}
+		kvm_run->debug.arch.dr6 = dr6 | DR6_FIXED_1;
+		kvm_run->debug.arch.dr7 = vmcs_readl(GUEST_DR7);
+		/* fall through */
+	case BP_VECTOR:
 		kvm_run->exit_reason = KVM_EXIT_DEBUG;
 		kvm_run->debug.arch.pc = vmcs_readl(GUEST_CS_BASE) + rip;
 		kvm_run->debug.arch.exception = ex_no;
-	} else {
+		break;
+	default:
 		kvm_run->exit_reason = KVM_EXIT_EXCEPTION;
 		kvm_run->ex.exception = ex_no;
 		kvm_run->ex.error_code = error_code;
+		break;
 	}
 	return 0;
 }
@@ -2784,21 +2797,44 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	unsigned long val;
 	int dr, reg;
 
-	/*
-	 * FIXME: this code assumes the host is debugging the guest.
-	 *        need to deal with guest debugging itself too.
-	 */
+	dr = vmcs_readl(GUEST_DR7);
+	if (dr & DR7_GD) {
+		/*
+		 * As the vm-exit takes precedence over the debug trap, we
+		 * need to emulate the latter, either for the host or the
+		 * guest debugging itself.
+		 */
+		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) {
+			kvm_run->debug.arch.dr6 = vcpu->arch.dr6;
+			kvm_run->debug.arch.dr7 = dr;
+			kvm_run->debug.arch.pc =
+				vmcs_readl(GUEST_CS_BASE) +
+				vmcs_readl(GUEST_RIP);
+			kvm_run->debug.arch.exception = DB_VECTOR;
+			kvm_run->exit_reason = KVM_EXIT_DEBUG;
+			return 0;
+		} else {
+			vcpu->arch.dr7 &= ~DR7_GD;
+			vcpu->arch.dr6 |= DR6_BD;
+			vmcs_writel(GUEST_DR7, vcpu->arch.dr7);
+			kvm_queue_exception(vcpu, DB_VECTOR);
+			return 1;
+		}
+	}
+
 	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
-	dr = exit_qualification & 7;
-	reg = (exit_qualification >> 8) & 15;
-	if (exit_qualification & 16) {
-		/* mov from dr */
+	dr = exit_qualification & DEBUG_REG_ACCESS_NUM;
+	reg = DEBUG_REG_ACCESS_REG(exit_qualification);
+	if (exit_qualification & TYPE_MOV_FROM_DR) {
 		switch (dr) {
+		case 0 ... 3:
+			val = vcpu->arch.db[dr];
+			break;
 		case 6:
-			val = 0xffff0ff0;
+			val = vcpu->arch.dr6;
 			break;
 		case 7:
-			val = 0x400;
+			val = vcpu->arch.dr7;
 			break;
 		default:
 			val = 0;
@@ -2806,7 +2842,38 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 		kvm_register_write(vcpu, reg, val);
 		KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler);
 	} else {
-		/* mov to dr */
+		val = vcpu->arch.regs[reg];
+		switch (dr) {
+		case 0 ... 3:
+			vcpu->arch.db[dr] = val;
+			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)
+				kvm_queue_exception(vcpu, UD_VECTOR);
+			break;
+		case 6:
+			if (val & 0xffffffff00000000ULL) {
+				kvm_queue_exception(vcpu, GP_VECTOR);
+				break;
+			}
+			vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
+			break;
+		case 7:
+			if (val & 0xffffffff00000000ULL) {
+				kvm_queue_exception(vcpu, GP_VECTOR);
+				break;
+			}
+			vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
+			if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
+				vmcs_writel(GUEST_DR7, vcpu->arch.dr7);
+				vcpu->arch.switch_db_regs =
+					(val & DR7_BP_EN_MASK);
+			}
+			break;
+		}
+		KVMTRACE_2D(DR_WRITE, vcpu, (u32)dr, (u32)val, handler);
 	}
 	skip_emulated_instruction(vcpu);
 	return 1;
@@ -2957,7 +3024,18 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	}
 	tss_selector = exit_qualification;
 
-	return kvm_task_switch(vcpu, tss_selector, reason);
+	if (!kvm_task_switch(vcpu, tss_selector, reason))
+		return 0;
+
+	/* clear all local breakpoint enable flags */
+	vmcs_writel(GUEST_DR7, vmcs_readl(GUEST_DR7) & ~55);
+
+	/*
+	 * TODO: What about debug traps on tss switch?
+	 *       Are we supposed to inject them and update dr6?
+	 */
+
+	return 1;
 }
 
 static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -3356,6 +3434,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	 */
 	vmcs_writel(HOST_CR0, read_cr0());
 
+	set_debugreg(vcpu->arch.dr6, 6);
+
 	asm(
 		/* Store host registers */
 		"push %%"R"dx; push %%"R"bp;"
@@ -3450,6 +3530,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP));
 	vcpu->arch.regs_dirty = 0;
 
+	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);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 10cc1c1..18061b6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3013,10 +3013,34 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
 	kvm_guest_enter();
 
+	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);
+		set_debugreg(vcpu->arch.eff_db[2], 2);
+		set_debugreg(vcpu->arch.eff_db[3], 3);
+	}
 
 	KVMTRACE_0D(VMENTRY, vcpu, entryexit);
 	kvm_x86_ops->run(vcpu, kvm_run);
 
+	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);
+	}
+	set_debugreg(vcpu->arch.host_dr6, 6);
+	set_debugreg(vcpu->arch.host_dr7, 7);
+
 	vcpu->guest_mode = 0;
 	local_irq_enable();
 
@@ -4028,6 +4052,11 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu)
 	vcpu->arch.nmi_pending = false;
 	vcpu->arch.nmi_injected = false;
 
+	vcpu->arch.switch_db_regs = 0;
+	memset(vcpu->arch.db, 0, sizeof(vcpu->arch.db));
+	vcpu->arch.dr6 = DR6_FIXED_1;
+	vcpu->arch.dr7 = DR7_FIXED_1;
+
 	return kvm_x86_ops->vcpu_reset(vcpu);
 }
 


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

* [PATCH 2/5] KVM: New guest debug interface
  2008-11-27 11:43 [PATCH 0/5] KVM: Improved guest debugging / debug register emulation Jan Kiszka
                   ` (2 preceding siblings ...)
  2008-11-27 11:43 ` [PATCH 1/5] VMX: Support for injecting software exceptions Jan Kiszka
@ 2008-11-27 11:43 ` Jan Kiszka
  2008-12-07  9:55   ` Avi Kivity
  2008-11-27 11:43 ` [PATCH 4/5] KVM: x86: Virtualize debug registers Jan Kiszka
  4 siblings, 1 reply; 18+ messages in thread
From: Jan Kiszka @ 2008-11-27 11:43 UTC (permalink / raw)
  To: kvm; +Cc: Avi Kivity, Hollis Blanchard, Joerg Roedel

This rips out the support for KVM_DEBUG_GUEST and introduces a new IOCTL
instead: KVM_SET_GUEST_DEBUG. The IOCTL payload consists of a generic
part, controlling the "main switch" and the single-step feature. The
arch specific part adds an x86 interface for intercepting both types of
debug exceptions separately and re-injecting them when the host was not
interested. Moveover, the foundation for guest debugging via debug
registers is layed.

To signal breakpoint events properly back to userland, an arch-specific
data block is now returned along KVM_EXIT_DEBUG. For x86, the arch block
contains the PC, the debug exception, and relevant debug registers to
tell debug events properly apart.

The availability of this new interface is signaled by
KVM_CAP_SET_GUEST_DEBUG. Empty stubs for not yet supported archs are
provided.

Note that both SVM and VTX are supported, but only the latter was tested
yet. Based on the experience with all those VTX corner case, I would be
fairly surprised if SVM will work out of the box.

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

 arch/ia64/include/asm/kvm.h     |    7 +++
 arch/ia64/kvm/kvm-ia64.c        |    4 +-
 arch/powerpc/include/asm/kvm.h  |    7 +++
 arch/powerpc/kvm/powerpc.c      |    4 +-
 arch/s390/include/asm/kvm.h     |    7 +++
 arch/s390/kvm/kvm-s390.c        |    4 +-
 arch/x86/include/asm/kvm.h      |   18 ++++++++
 arch/x86/include/asm/kvm_host.h |    9 ----
 arch/x86/kvm/svm.c              |   50 ++++++++++++++++++++-
 arch/x86/kvm/vmx.c              |   93 +++++++++++++++------------------------
 arch/x86/kvm/x86.c              |   14 +++---
 include/linux/kvm.h             |   51 +++++++++++++++------
 include/linux/kvm_host.h        |    6 +--
 virt/kvm/kvm_main.c             |    6 +--
 14 files changed, 179 insertions(+), 101 deletions(-)

diff --git a/arch/ia64/include/asm/kvm.h b/arch/ia64/include/asm/kvm.h
index f38472a..c4ab145 100644
--- a/arch/ia64/include/asm/kvm.h
+++ b/arch/ia64/include/asm/kvm.h
@@ -208,4 +208,11 @@ struct kvm_sregs {
 struct kvm_fpu {
 };
 
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
 #endif
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index b4d24e2..6d5c177 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1316,8 +1316,8 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 	return -EINVAL;
 }
 
-int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
-		struct kvm_debug_guest *dbg)
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+					struct kvm_guest_debug *dbg)
 {
 	return -EINVAL;
 }
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
index f993e41..755f1b1 100644
--- a/arch/powerpc/include/asm/kvm.h
+++ b/arch/powerpc/include/asm/kvm.h
@@ -52,4 +52,11 @@ struct kvm_fpu {
 	__u64 fpr[32];
 };
 
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
 #endif /* __LINUX_KVM_POWERPC_H */
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 0745b6d..00a7d91 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -229,8 +229,8 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 	kvmppc_core_vcpu_put(vcpu);
 }
 
-int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
-                                    struct kvm_debug_guest *dbg)
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+					struct kvm_guest_debug *dbg)
 {
 	int i;
 
diff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/asm/kvm.h
index d74002f..0d56683 100644
--- a/arch/s390/include/asm/kvm.h
+++ b/arch/s390/include/asm/kvm.h
@@ -42,4 +42,11 @@ struct kvm_fpu {
 	__u64 fprs[16];
 };
 
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
 #endif
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 8b00eb2..619b739 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -413,8 +413,8 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
 	return -EINVAL; /* not implemented yet */
 }
 
-int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
-				    struct kvm_debug_guest *dbg)
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+					struct kvm_guest_debug *dbg)
 {
 	return -EINVAL; /* not implemented yet */
 }
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index b95162a..4baf107 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -205,6 +205,24 @@ struct kvm_pit_channel_state {
 	__s64 count_load_time;
 };
 
+struct kvm_debug_exit_arch {
+	__u32 exception;
+	__u32 pad;
+	__u64 pc;
+	__u64 dr6;
+	__u64 dr7;
+};
+
+#define KVM_GUESTDBG_USE_SW_BP		0x00010000
+#define KVM_GUESTDBG_USE_HW_BP		0x00020000
+#define KVM_GUESTDBG_INJECT_DB		0x00040000
+#define KVM_GUESTDBG_INJECT_BP		0x00080000
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+	__u64 debugreg[8];
+};
+
 struct kvm_pit_state {
 	struct kvm_pit_channel_state channels[3];
 };
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f58f7eb..7151b08 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -134,12 +134,6 @@ enum {
 
 #define KVM_NR_MEM_OBJS 40
 
-struct kvm_guest_debug {
-	int enabled;
-	unsigned long bp[4];
-	int singlestep;
-};
-
 /*
  * We don't want allocation failures within the mmu code, so we preallocate
  * enough memory for a single page fault in a cache.
@@ -441,8 +435,7 @@ struct kvm_x86_ops {
 	void (*vcpu_put)(struct kvm_vcpu *vcpu);
 
 	int (*set_guest_debug)(struct kvm_vcpu *vcpu,
-			       struct kvm_debug_guest *dbg);
-	void (*guest_debug_pre)(struct kvm_vcpu *vcpu);
+			       struct kvm_guest_debug *dbg);
 	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
 	int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 	u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 1452851..b6cd047 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -905,9 +905,32 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
 
 }
 
-static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
+static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
 {
-	return -EOPNOTSUPP;
+	int old_debug = vcpu->guest_debug;
+	struct vcpu_svm *svm = to_svm(vcpu);
+
+	vcpu->guest_debug = dbg->control;
+
+	svm->vmcb->control.intercept_exceptions &=
+		~((1 << DB_VECTOR) | (1 << BP_VECTOR));
+	if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
+		if (vcpu->guest_debug &
+		    (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
+			svm->vmcb->control.intercept_exceptions |=
+				1 << DB_VECTOR;
+		if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
+			svm->vmcb->control.intercept_exceptions |=
+				1 << BP_VECTOR;
+	} else
+		vcpu->guest_debug = 0;
+
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+		svm->vmcb->save.rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
+	else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
+		svm->vmcb->save.rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
+
+	return 0;
 }
 
 static int svm_get_irq(struct kvm_vcpu *vcpu)
@@ -1031,6 +1054,27 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 	return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
 }
 
+static int db_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+{
+	if (!(svm->vcpu.guest_debug &
+	      (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
+		kvm_queue_exception(&svm->vcpu, DB_VECTOR);
+		return 1;
+	}
+	kvm_run->exit_reason = KVM_EXIT_DEBUG;
+	kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip;
+	kvm_run->debug.arch.exception = DB_VECTOR;
+	return 0;
+}
+
+static int bp_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+{
+	kvm_run->exit_reason = KVM_EXIT_DEBUG;
+	kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip;
+	kvm_run->debug.arch.exception = BP_VECTOR;
+	return 0;
+}
+
 static int ud_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
 	int er;
@@ -1417,6 +1461,8 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
 	[SVM_EXIT_WRITE_DR3]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_DR5]			= 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,
 	[SVM_EXIT_EXCP_BASE + UD_VECTOR]	= ud_interception,
 	[SVM_EXIT_EXCP_BASE + PF_VECTOR] 	= pf_interception,
 	[SVM_EXIT_EXCP_BASE + NM_VECTOR] 	= nm_interception,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index da7cc03..3a422dc 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -480,8 +480,13 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
 	eb = (1u << PF_VECTOR) | (1u << UD_VECTOR);
 	if (!vcpu->fpu_active)
 		eb |= 1u << NM_VECTOR;
-	if (vcpu->guest_debug.enabled)
-		eb |= 1u << DB_VECTOR;
+	if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
+		if (vcpu->guest_debug &
+		    (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
+			eb |= 1u << DB_VECTOR;
+		if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
+			eb |= 1u << BP_VECTOR;
+	}
 	if (vcpu->arch.rmode.active)
 		eb = ~0;
 	if (vm_need_ept())
@@ -1002,40 +1007,23 @@ static void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 	}
 }
 
-static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
+static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
 {
-	unsigned long dr7 = 0x400;
-	int old_singlestep;
-
-	old_singlestep = vcpu->guest_debug.singlestep;
-
-	vcpu->guest_debug.enabled = dbg->enabled;
-	if (vcpu->guest_debug.enabled) {
-		int i;
-
-		dr7 |= 0x200;  /* exact */
-		for (i = 0; i < 4; ++i) {
-			if (!dbg->breakpoints[i].enabled)
-				continue;
-			vcpu->guest_debug.bp[i] = dbg->breakpoints[i].address;
-			dr7 |= 2 << (i*2);    /* global enable */
-			dr7 |= 0 << (i*4+16); /* execution breakpoint */
-		}
-
-		vcpu->guest_debug.singlestep = dbg->singlestep;
-	} else
-		vcpu->guest_debug.singlestep = 0;
+	int old_debug = vcpu->guest_debug;
+	unsigned long flags;
 
-	if (old_singlestep && !vcpu->guest_debug.singlestep) {
-		unsigned long flags;
+	vcpu->guest_debug = dbg->control;
+	if (!(vcpu->guest_debug & KVM_GUESTDBG_ENABLE))
+		vcpu->guest_debug = 0;
 
-		flags = vmcs_readl(GUEST_RFLAGS);
+	flags = vmcs_readl(GUEST_RFLAGS);
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+		flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
+	else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
 		flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
-		vmcs_writel(GUEST_RFLAGS, flags);
-	}
+	vmcs_writel(GUEST_RFLAGS, flags);
 
 	update_exception_bitmap(vcpu);
-	vmcs_writel(GUEST_DR7, dr7);
 
 	return 0;
 }
@@ -2539,24 +2527,6 @@ static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
 	return 0;
 }
 
-static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu)
-{
-	struct kvm_guest_debug *dbg = &vcpu->guest_debug;
-
-	set_debugreg(dbg->bp[0], 0);
-	set_debugreg(dbg->bp[1], 1);
-	set_debugreg(dbg->bp[2], 2);
-	set_debugreg(dbg->bp[3], 3);
-
-	if (dbg->singlestep) {
-		unsigned long flags;
-
-		flags = vmcs_readl(GUEST_RFLAGS);
-		flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
-		vmcs_writel(GUEST_RFLAGS, flags);
-	}
-}
-
 static int handle_rmode_exception(struct kvm_vcpu *vcpu,
 				  int vec, u32 err_code)
 {
@@ -2573,9 +2543,17 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
 	 *        the required debugging infrastructure rework.
 	 */
 	switch (vec) {
-	case DE_VECTOR:
 	case DB_VECTOR:
+		if (vcpu->guest_debug &
+		    (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
+			return 0;
+		kvm_queue_exception(vcpu, vec);
+		return 1;
 	case BP_VECTOR:
+		if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
+			return 0;
+		/* fall through */
+	case DE_VECTOR:
 	case OF_VECTOR:
 	case BR_VECTOR:
 	case UD_VECTOR:
@@ -2592,7 +2570,7 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
 static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	u32 intr_info, error_code;
+	u32 intr_info, ex_no, error_code;
 	unsigned long cr2, rip;
 	u32 vect_info;
 	enum emulation_result er;
@@ -2652,14 +2630,16 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 		return 1;
 	}
 
-	if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) ==
-	    (INTR_TYPE_HARD_EXCEPTION | 1)) {
+	ex_no = intr_info & INTR_INFO_VECTOR_MASK;
+	if (ex_no == DB_VECTOR || ex_no == BP_VECTOR) {
 		kvm_run->exit_reason = KVM_EXIT_DEBUG;
-		return 0;
+		kvm_run->debug.arch.pc = vmcs_readl(GUEST_CS_BASE) + rip;
+		kvm_run->debug.arch.exception = ex_no;
+	} else {
+		kvm_run->exit_reason = KVM_EXIT_EXCEPTION;
+		kvm_run->ex.exception = ex_no;
+		kvm_run->ex.error_code = error_code;
 	}
-	kvm_run->exit_reason = KVM_EXIT_EXCEPTION;
-	kvm_run->ex.exception = intr_info & INTR_INFO_VECTOR_MASK;
-	kvm_run->ex.error_code = error_code;
 	return 0;
 }
 
@@ -3618,7 +3598,6 @@ static struct kvm_x86_ops vmx_x86_ops = {
 	.vcpu_put = vmx_vcpu_put,
 
 	.set_guest_debug = set_guest_debug,
-	.guest_debug_pre = kvm_guest_debug_pre,
 	.get_msr = vmx_get_msr,
 	.set_msr = vmx_set_msr,
 	.get_segment_base = vmx_get_segment_base,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 7a2aeba..10cc1c1 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2993,9 +2993,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 		goto out;
 	}
 
-	if (vcpu->guest_debug.enabled)
-		kvm_x86_ops->guest_debug_pre(vcpu);
-
 	vcpu->guest_mode = 1;
 	/*
 	 * Make sure that guest_mode assignment won't happen after
@@ -3211,7 +3208,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 	/*
 	 * Don't leak debug flags in case they were set for guest debugging
 	 */
-	if (vcpu->guest_debug.enabled && vcpu->guest_debug.singlestep)
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
 		regs->rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
 
 	vcpu_put(vcpu);
@@ -3830,8 +3827,8 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
-int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
-				    struct kvm_debug_guest *dbg)
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+					struct kvm_guest_debug *dbg)
 {
 	int r;
 
@@ -3839,6 +3836,11 @@ int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
 
 	r = kvm_x86_ops->set_guest_debug(vcpu, dbg);
 
+	if (dbg->control & KVM_GUESTDBG_INJECT_DB)
+		kvm_queue_exception(vcpu, DB_VECTOR);
+	else if (dbg->control & KVM_GUESTDBG_INJECT_BP)
+		kvm_queue_exception(vcpu, BP_VECTOR);
+
 	vcpu_put(vcpu);
 
 	return r;
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 0997e6f..707fa24 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -129,6 +129,7 @@ struct kvm_run {
 			__u64 data_offset; /* relative to kvm_run start */
 		} io;
 		struct {
+			struct kvm_debug_exit_arch arch;
 		} debug;
 		/* KVM_EXIT_MMIO */
 		struct {
@@ -220,21 +221,6 @@ struct kvm_interrupt {
 	__u32 irq;
 };
 
-struct kvm_breakpoint {
-	__u32 enabled;
-	__u32 padding;
-	__u64 address;
-};
-
-/* for KVM_DEBUG_GUEST */
-struct kvm_debug_guest {
-	/* int */
-	__u32 enabled;
-	__u32 pad;
-	struct kvm_breakpoint breakpoints[4];
-	__u32 singlestep;
-};
-
 /* for KVM_GET_DIRTY_LOG */
 struct kvm_dirty_log {
 	__u32 slot;
@@ -295,6 +281,17 @@ struct kvm_s390_interrupt {
 	__u64 parm64;
 };
 
+/* for KVM_SET_GUEST_DEBUG */
+
+#define KVM_GUESTDBG_ENABLE		0x00000001
+#define KVM_GUESTDBG_SINGLESTEP		0x00000002
+
+struct kvm_guest_debug {
+	__u32 control;
+	__u32 pad;
+	struct kvm_guest_debug_arch arch;
+};
+
 #define KVM_TRC_SHIFT           16
 /*
  * kvm trace categories
@@ -395,6 +392,7 @@ struct kvm_trace_rec {
 #if defined(CONFIG_X86)
 #define KVM_CAP_DEVICE_MSI 20
 #endif
+#define KVM_CAP_SET_GUEST_DEBUG 21
 
 /*
  * ioctls for VM fds
@@ -439,7 +437,8 @@ struct kvm_trace_rec {
 #define KVM_SET_SREGS             _IOW(KVMIO,  0x84, struct kvm_sregs)
 #define KVM_TRANSLATE             _IOWR(KVMIO, 0x85, struct kvm_translation)
 #define KVM_INTERRUPT             _IOW(KVMIO,  0x86, struct kvm_interrupt)
-#define KVM_DEBUG_GUEST           _IOW(KVMIO,  0x87, struct kvm_debug_guest)
+/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */
+#define KVM_DEBUG_GUEST           __KVM_DEPRECATED_DEBUG_GUEST
 #define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
 #define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
 #define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
@@ -468,6 +467,26 @@ struct kvm_trace_rec {
 #define KVM_SET_MP_STATE          _IOW(KVMIO,  0x99, struct kvm_mp_state)
 /* Available with KVM_CAP_NMI */
 #define KVM_NMI                   _IO(KVMIO,  0x9a)
+/* Available with KVM_CAP_SET_GUEST_DEBUG */
+#define KVM_SET_GUEST_DEBUG       _IOW(KVMIO,  0x9a, struct kvm_guest_debug)
+
+/*
+ * Deprecated interfaces
+ */
+struct kvm_breakpoint {
+	__u32 enabled;
+	__u32 padding;
+	__u64 address;
+};
+
+struct kvm_debug_guest {
+	__u32 enabled;
+	__u32 pad;
+	struct kvm_breakpoint breakpoints[4];
+	__u32 singlestep;
+};
+
+#define __KVM_DEPRECATED_DEBUG_GUEST _IOW(KVMIO,  0x87, struct kvm_debug_guest)
 
 #define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
 #define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 8091a4d..fc1475a 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -73,7 +73,7 @@ struct kvm_vcpu {
 	struct kvm_run *run;
 	int guest_mode;
 	unsigned long requests;
-	struct kvm_guest_debug guest_debug;
+	unsigned long guest_debug;
 	int fpu_active;
 	int guest_fpu_loaded;
 	wait_queue_head_t wq;
@@ -255,8 +255,8 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
 				    struct kvm_mp_state *mp_state);
 int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 				    struct kvm_mp_state *mp_state);
-int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
-				    struct kvm_debug_guest *dbg);
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+					struct kvm_guest_debug *dbg);
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);
 
 int kvm_arch_init(void *opaque);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 54d25e6..103793a 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1672,13 +1672,13 @@ out_free2:
 		r = 0;
 		break;
 	}
-	case KVM_DEBUG_GUEST: {
-		struct kvm_debug_guest dbg;
+	case KVM_SET_GUEST_DEBUG: {
+		struct kvm_guest_debug dbg;
 
 		r = -EFAULT;
 		if (copy_from_user(&dbg, argp, sizeof dbg))
 			goto out;
-		r = kvm_arch_vcpu_ioctl_debug_guest(vcpu, &dbg);
+		r = kvm_arch_vcpu_ioctl_set_guest_debug(vcpu, &dbg);
 		if (r)
 			goto out;
 		r = 0;


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

* [PATCH 3/5] KVM: VMX: Ensure interruptibility when single-stepping
  2008-11-27 11:43 [PATCH 0/5] KVM: Improved guest debugging / debug register emulation Jan Kiszka
  2008-11-27 11:43 ` [PATCH 5/5] KVM: x86: Wire-up hardware breakpoints for guest debugging Jan Kiszka
@ 2008-11-27 11:43 ` Jan Kiszka
  2008-12-07 10:05   ` Avi Kivity
  2008-11-27 11:43 ` [PATCH 1/5] VMX: Support for injecting software exceptions Jan Kiszka
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 18+ messages in thread
From: Jan Kiszka @ 2008-11-27 11:43 UTC (permalink / raw)
  To: kvm; +Cc: Avi Kivity, Hollis Blanchard, Joerg Roedel

When single-stepping, we have to ensure that the INT1 can make it
through even if the guest itself is uninterruptible due to MOV SS or
STI. VMENTRY will fail otherwise.

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

 arch/x86/kvm/vmx.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 3a422dc..8e83102 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1010,6 +1010,7 @@ static void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
 static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
 {
 	int old_debug = vcpu->guest_debug;
+	u32 interruptibility;
 	unsigned long flags;
 
 	vcpu->guest_debug = dbg->control;
@@ -1017,9 +1018,14 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
 		vcpu->guest_debug = 0;
 
 	flags = vmcs_readl(GUEST_RFLAGS);
-	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
 		flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
-	else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
+		/* We must be interruptible when single-stepping */
+		interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+		if (interruptibility & 3)
+			vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
+				     interruptibility & ~3);
+	} else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
 		flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
 	vmcs_writel(GUEST_RFLAGS, flags);
 


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

* Re: [PATCH 2/5] KVM: New guest debug interface
  2008-11-27 11:43 ` [PATCH 2/5] KVM: New guest debug interface Jan Kiszka
@ 2008-12-07  9:55   ` Avi Kivity
  2008-12-08  9:13     ` Jan Kiszka
  0 siblings, 1 reply; 18+ messages in thread
From: Avi Kivity @ 2008-12-07  9:55 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Jan Kiszka wrote:
> This rips out the support for KVM_DEBUG_GUEST and introduces a new IOCTL
> instead: KVM_SET_GUEST_DEBUG. The IOCTL payload consists of a generic
> part, controlling the "main switch" and the single-step feature. The
> arch specific part adds an x86 interface for intercepting both types of
> debug exceptions separately and re-injecting them when the host was not
> interested. Moveover, the foundation for guest debugging via debug
> registers is layed.
>   

Have you tested compile-time compatibility with older userspace?

> Note that both SVM and VTX are supported, but only the latter was tested
> yet. Based on the experience with all those VTX corner case, I would be
> fairly surprised if SVM will work out of the box.
>
>   

I'd like svm to work before applying.

> @@ -439,7 +437,8 @@ struct kvm_trace_rec {
>  #define KVM_SET_SREGS             _IOW(KVMIO,  0x84, struct kvm_sregs)
>  #define KVM_TRANSLATE             _IOWR(KVMIO, 0x85, struct kvm_translation)
>  #define KVM_INTERRUPT             _IOW(KVMIO,  0x86, struct kvm_interrupt)
> -#define KVM_DEBUG_GUEST           _IOW(KVMIO,  0x87, struct kvm_debug_guest)
> +/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */
> +#define KVM_DEBUG_GUEST           __KVM_DEPRECATED_DEBUG_GUEST
>  #define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
>  #define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
>  #define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
> @@ -468,6 +467,26 @@ struct kvm_trace_rec {
>  #define KVM_SET_MP_STATE          _IOW(KVMIO,  0x99, struct kvm_mp_state)
>  /* Available with KVM_CAP_NMI */
>  #define KVM_NMI                   _IO(KVMIO,  0x9a)
> +/* Available with KVM_CAP_SET_GUEST_DEBUG */
> +#define KVM_SET_GUEST_DEBUG       _IOW(KVMIO,  0x9a, struct kvm_guest_debug)
> +
>   

0x9b...


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


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

* Re: [PATCH 3/5] KVM: VMX: Ensure interruptibility when single-stepping
  2008-11-27 11:43 ` [PATCH 3/5] KVM: VMX: Ensure interruptibility when single-stepping Jan Kiszka
@ 2008-12-07 10:05   ` Avi Kivity
  2008-12-08  9:17     ` Jan Kiszka
  2008-12-11 19:15     ` [PATCH] KVM: VMX: Allow single-stepping when interruptible Jan Kiszka
  0 siblings, 2 replies; 18+ messages in thread
From: Avi Kivity @ 2008-12-07 10:05 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Jan Kiszka wrote:
> When single-stepping, we have to ensure that the INT1 can make it
> through even if the guest itself is uninterruptible due to MOV SS or
> STI. VMENTRY will fail otherwise.
>
> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
> ---
>
>  arch/x86/kvm/vmx.c |   10 ++++++++--
>  1 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index 3a422dc..8e83102 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -1010,6 +1010,7 @@ static void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
>  static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
>  {
>  	int old_debug = vcpu->guest_debug;
> +	u32 interruptibility;
>  	unsigned long flags;
>  
>  	vcpu->guest_debug = dbg->control;
> @@ -1017,9 +1018,14 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
>  		vcpu->guest_debug = 0;
>  
>  	flags = vmcs_readl(GUEST_RFLAGS);
> -	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
> +	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
>  		flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
> -	else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
> +		/* We must be interruptible when single-stepping */
> +		interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
> +		if (interruptibility & 3)
> +			vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
> +				     interruptibility & ~3);
>   

Could just write unconditionally - it's not like the write has any 
effect on speed.  vmcs_clear_bits() will do it cleanly.

But I'm worried about correctness.  Suppose we're singlestepping a sti; 
hlt sequence.  While we'll clear interruptibility, probably receive the 
debug trap (since that's a high priority exception), but then inject the 
interrupt before the hlt, hanging the guest.  So we probably need to 
restore interruptibility on exit.

This looks like a good candidate for a test case.

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


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

* Re: [PATCH 2/5] KVM: New guest debug interface
  2008-12-07  9:55   ` Avi Kivity
@ 2008-12-08  9:13     ` Jan Kiszka
  2008-12-08  9:34       ` Avi Kivity
  0 siblings, 1 reply; 18+ messages in thread
From: Jan Kiszka @ 2008-12-08  9:13 UTC (permalink / raw)
  To: Avi Kivity; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Avi Kivity wrote:
> Jan Kiszka wrote:
>> This rips out the support for KVM_DEBUG_GUEST and introduces a new IOCTL
>> instead: KVM_SET_GUEST_DEBUG. The IOCTL payload consists of a generic
>> part, controlling the "main switch" and the single-step feature. The
>> arch specific part adds an x86 interface for intercepting both types of
>> debug exceptions separately and re-injecting them when the host was not
>> interested. Moveover, the foundation for guest debugging via debug
>> registers is layed.
>>   
> 
> Have you tested compile-time compatibility with older userspace?

Yes, works.

> 
>> Note that both SVM and VTX are supported, but only the latter was tested
>> yet. Based on the experience with all those VTX corner case, I would be
>> fairly surprised if SVM will work out of the box.
>>
>>   
> 
> I'd like svm to work before applying.

To validate the design?

I will see if I can organize an SVM box, but I can't promise when I'll
be able to do the testing. Anyone willing to contribute time on this
would be warmly welcome!

> 
>> @@ -439,7 +437,8 @@ struct kvm_trace_rec {
>>  #define KVM_SET_SREGS             _IOW(KVMIO,  0x84, struct kvm_sregs)
>>  #define KVM_TRANSLATE             _IOWR(KVMIO, 0x85, struct
>> kvm_translation)
>>  #define KVM_INTERRUPT             _IOW(KVMIO,  0x86, struct
>> kvm_interrupt)
>> -#define KVM_DEBUG_GUEST           _IOW(KVMIO,  0x87, struct
>> kvm_debug_guest)
>> +/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG
>> instead */
>> +#define KVM_DEBUG_GUEST           __KVM_DEPRECATED_DEBUG_GUEST
>>  #define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
>>  #define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
>>  #define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
>> @@ -468,6 +467,26 @@ struct kvm_trace_rec {
>>  #define KVM_SET_MP_STATE          _IOW(KVMIO,  0x99, struct
>> kvm_mp_state)
>>  /* Available with KVM_CAP_NMI */
>>  #define KVM_NMI                   _IO(KVMIO,  0x9a)
>> +/* Available with KVM_CAP_SET_GUEST_DEBUG */
>> +#define KVM_SET_GUEST_DEBUG       _IOW(KVMIO,  0x9a, struct
>> kvm_guest_debug)
>> +
>>   
> 
> 0x9b...

Oh, rebased a bit too often.

Jan

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

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

* Re: [PATCH 3/5] KVM: VMX: Ensure interruptibility when single-stepping
  2008-12-07 10:05   ` Avi Kivity
@ 2008-12-08  9:17     ` Jan Kiszka
  2008-12-11 19:15     ` [PATCH] KVM: VMX: Allow single-stepping when interruptible Jan Kiszka
  1 sibling, 0 replies; 18+ messages in thread
From: Jan Kiszka @ 2008-12-08  9:17 UTC (permalink / raw)
  To: Avi Kivity; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Avi Kivity wrote:
> Jan Kiszka wrote:
>> When single-stepping, we have to ensure that the INT1 can make it
>> through even if the guest itself is uninterruptible due to MOV SS or
>> STI. VMENTRY will fail otherwise.
>>
>> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
>> ---
>>
>>  arch/x86/kvm/vmx.c |   10 ++++++++--
>>  1 files changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>> index 3a422dc..8e83102 100644
>> --- a/arch/x86/kvm/vmx.c
>> +++ b/arch/x86/kvm/vmx.c
>> @@ -1010,6 +1010,7 @@ static void vmx_cache_reg(struct kvm_vcpu *vcpu,
>> enum kvm_reg reg)
>>  static int set_guest_debug(struct kvm_vcpu *vcpu, struct
>> kvm_guest_debug *dbg)
>>  {
>>      int old_debug = vcpu->guest_debug;
>> +    u32 interruptibility;
>>      unsigned long flags;
>>  
>>      vcpu->guest_debug = dbg->control;
>> @@ -1017,9 +1018,14 @@ static int set_guest_debug(struct kvm_vcpu
>> *vcpu, struct kvm_guest_debug *dbg)
>>          vcpu->guest_debug = 0;
>>  
>>      flags = vmcs_readl(GUEST_RFLAGS);
>> -    if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
>> +    if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
>>          flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
>> -    else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
>> +        /* We must be interruptible when single-stepping */
>> +        interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
>> +        if (interruptibility & 3)
>> +            vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
>> +                     interruptibility & ~3);
>>   
> 
> Could just write unconditionally - it's not like the write has any
> effect on speed.  vmcs_clear_bits() will do it cleanly.

OK.

> 
> But I'm worried about correctness.  Suppose we're singlestepping a sti;
> hlt sequence.  While we'll clear interruptibility, probably receive the
> debug trap (since that's a high priority exception), but then inject the
> interrupt before the hlt, hanging the guest.  So we probably need to
> restore interruptibility on exit.
> 
> This looks like a good candidate for a test case.

You're concern might be valid. Will dig into the test infrastructure.
Maybe it is a good idea to have something like the kgdb testsuite as
part of the kvm tests to check debugger regressions, not just this
special case.

Jan

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

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

* Re: [PATCH 2/5] KVM: New guest debug interface
  2008-12-08  9:13     ` Jan Kiszka
@ 2008-12-08  9:34       ` Avi Kivity
  2008-12-08  9:42         ` Jan Kiszka
  2008-12-08 13:47         ` Jan Kiszka
  0 siblings, 2 replies; 18+ messages in thread
From: Avi Kivity @ 2008-12-08  9:34 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Jan Kiszka wrote:
>>> Note that both SVM and VTX are supported, but only the latter was tested
>>> yet. Based on the experience with all those VTX corner case, I would be
>>> fairly surprised if SVM will work out of the box.
>>>
>>>   
>>>       
>> I'd like svm to work before applying.
>>     
>
> To validate the design?
>
>   

To make sure it doesn't oops, and to make sure it works.

> I will see if I can organize an SVM box, but I can't promise when I'll
> be able to do the testing. Anyone willing to contribute time on this
> would be warmly welcome!
>
>   

I happen to have an svm box.  How do you test this? play with gdb inside 
and outside the guest?

You could also try qemu's svm emulation, but it may be a little slow, 
and probably hasn't been well tested in these areas.

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.


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

* Re: [PATCH 2/5] KVM: New guest debug interface
  2008-12-08  9:34       ` Avi Kivity
@ 2008-12-08  9:42         ` Jan Kiszka
  2008-12-08 13:47         ` Jan Kiszka
  1 sibling, 0 replies; 18+ messages in thread
From: Jan Kiszka @ 2008-12-08  9:42 UTC (permalink / raw)
  To: Avi Kivity; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Avi Kivity wrote:
> Jan Kiszka wrote:
>>>> Note that both SVM and VTX are supported, but only the latter was
>>>> tested
>>>> yet. Based on the experience with all those VTX corner case, I would be
>>>> fairly surprised if SVM will work out of the box.
>>>>
>>>>         
>>> I'd like svm to work before applying.
>>>     
>>
>> To validate the design?
>>
>>   
> 
> To make sure it doesn't oops, and to make sure it works.
> 
>> I will see if I can organize an SVM box, but I can't promise when I'll
>> be able to do the testing. Anyone willing to contribute time on this
>> would be warmly welcome!
>>
>>   
> 
> I happen to have an svm box.  How do you test this? play with gdb inside
> and outside the guest?

For inside the box, I also use the kgdb testsuite (kgbts).

For guest debugging check, some manual interaction is required: Set a
breakpoint on a prominent symbol (my favorite is sys_execve), do some
single stepping, check that smp works (breakpoint hits on all vcpus),
add some watchpoint and check if it triggers at reasonable spots (I
recently did a short demo with first trapping hrtimer_start, grabbing
&timer->state and then set a watchpoint on that address to catch changes).

> 
> You could also try qemu's svm emulation, but it may be a little slow,
> and probably hasn't been well tested in these areas.
> 

Yeah, could be a supplemental test.

Jan

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

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

* Re: [PATCH 2/5] KVM: New guest debug interface
  2008-12-08  9:34       ` Avi Kivity
  2008-12-08  9:42         ` Jan Kiszka
@ 2008-12-08 13:47         ` Jan Kiszka
  2008-12-08 14:57           ` Avi Kivity
  1 sibling, 1 reply; 18+ messages in thread
From: Jan Kiszka @ 2008-12-08 13:47 UTC (permalink / raw)
  To: Avi Kivity; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Avi Kivity wrote:
> Jan Kiszka wrote:
>>>> Note that both SVM and VTX are supported, but only the latter was
>>>> tested
>>>> yet. Based on the experience with all those VTX corner case, I would be
>>>> fairly surprised if SVM will work out of the box.
>>>>
>>>>         
>>> I'd like svm to work before applying.
>>>     
>>
>> To validate the design?
>>
>>   
> 
> To make sure it doesn't oops, and to make sure it works.
> 
>> I will see if I can organize an SVM box, but I can't promise when I'll
>> be able to do the testing. Anyone willing to contribute time on this
>> would be warmly welcome!
>>
>>   
> 
> I happen to have an svm box.  How do you test this? play with gdb inside
> and outside the guest?
> 
> You could also try qemu's svm emulation, but it may be a little slow,
> and probably hasn't been well tested in these areas.

FYI: I just passed the kgdbts test with some Linux guest on an Opteron
2216. Also using hbreak with gdb inside the guest appears to work. There
are just a few to-be-analyzed guest lockups/kernel panics that may
relate to the fact that the kernels were build for Intel CPUs. On the
other hand, it would be far too simple if it worked already - compared
to the pain I went through with VMX...

Jan

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

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

* Re: [PATCH 2/5] KVM: New guest debug interface
  2008-12-08 13:47         ` Jan Kiszka
@ 2008-12-08 14:57           ` Avi Kivity
  2008-12-08 15:17             ` Jan Kiszka
  0 siblings, 1 reply; 18+ messages in thread
From: Avi Kivity @ 2008-12-08 14:57 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Jan Kiszka wrote:
> FYI: I just passed the kgdbts test with some Linux guest on an Opteron
> 2216. Also using hbreak with gdb inside the guest appears to work. There
> are just a few to-be-analyzed guest lockups/kernel panics that may
> relate to the fact that the kernels were build for Intel CPUs. On the
> other hand, it would be far too simple if it worked already - compared
> to the pain I went through with VMX...
>   

So long as it doesn't crash, this functionality is far enough from 
mainstream use.

btw, is it possible to emulate the old interface on top of the new 
implementation?  I feel unconfortable with dropping an interface (albeit 
an unused one) without even a warning.

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


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

* Re: [PATCH 2/5] KVM: New guest debug interface
  2008-12-08 14:57           ` Avi Kivity
@ 2008-12-08 15:17             ` Jan Kiszka
  2008-12-10  8:48               ` Avi Kivity
  0 siblings, 1 reply; 18+ messages in thread
From: Jan Kiszka @ 2008-12-08 15:17 UTC (permalink / raw)
  To: Avi Kivity; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Avi Kivity wrote:
> Jan Kiszka wrote:
>> FYI: I just passed the kgdbts test with some Linux guest on an Opteron
>> 2216. Also using hbreak with gdb inside the guest appears to work. There
>> are just a few to-be-analyzed guest lockups/kernel panics that may
>> relate to the fact that the kernels were build for Intel CPUs. On the
>> other hand, it would be far too simple if it worked already - compared
>> to the pain I went through with VMX...
>>   
> 
> So long as it doesn't crash, this functionality is far enough from
> mainstream use.

I would love to dig a bit deeper, doing more SMP tests, maybe also
adding userspace NMI support to SVM at this chance, but I was just
called away again. Hope to find some time next week, we'll see.

> 
> btw, is it possible to emulate the old interface on top of the new
> implementation?  I feel unconfortable with dropping an interface (albeit
> an unused one) without even a warning.

Would be possible, I guess - but do we really have to care? It only
worked for VMX, only on UP, qemu has no support for it (I'm planning to
submit the new interface once it's merged and settled), and I don't
think many people actually touched the old one so far. And those who may
throw the old IOCTL at a new kernel will get a proper error on return.
Is this problematic?

Jan

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

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

* Re: [PATCH 2/5] KVM: New guest debug interface
  2008-12-08 15:17             ` Jan Kiszka
@ 2008-12-10  8:48               ` Avi Kivity
  0 siblings, 0 replies; 18+ messages in thread
From: Avi Kivity @ 2008-12-10  8:48 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: kvm, Hollis Blanchard, Joerg Roedel

Jan Kiszka wrote:
>> btw, is it possible to emulate the old interface on top of the new
>> implementation?  I feel unconfortable with dropping an interface (albeit
>> an unused one) without even a warning.
>>     
>
> Would be possible, I guess - but do we really have to care? It only
> worked for VMX, only on UP, qemu has no support for it (I'm planning to
> submit the new interface once it's merged and settled), and I don't
> think many people actually touched the old one so far. And those who may
> throw the old IOCTL at a new kernel will get a proper error on return.
> Is this problematic?
>   

No, just exploring our options.  I'm okay with dropping the old 
implementation.

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


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

* [PATCH] KVM: VMX: Allow single-stepping when interruptible
  2008-12-07 10:05   ` Avi Kivity
  2008-12-08  9:17     ` Jan Kiszka
@ 2008-12-11 19:15     ` Jan Kiszka
  1 sibling, 0 replies; 18+ messages in thread
From: Jan Kiszka @ 2008-12-11 19:15 UTC (permalink / raw)
  To: Avi Kivity; +Cc: kvm, Yang, Sheng

Avi Kivity wrote:
> Jan Kiszka wrote:
>> When single-stepping, we have to ensure that the INT1 can make it
>> through even if the guest itself is uninterruptible due to MOV SS or
>> STI. VMENTRY will fail otherwise.
>>
>> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
>> ---
>>
>>  arch/x86/kvm/vmx.c |   10 ++++++++--
>>  1 files changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>> index 3a422dc..8e83102 100644
>> --- a/arch/x86/kvm/vmx.c
>> +++ b/arch/x86/kvm/vmx.c
>> @@ -1010,6 +1010,7 @@ static void vmx_cache_reg(struct kvm_vcpu *vcpu,
>> enum kvm_reg reg)
>>  static int set_guest_debug(struct kvm_vcpu *vcpu, struct
>> kvm_guest_debug *dbg)
>>  {
>>      int old_debug = vcpu->guest_debug;
>> +    u32 interruptibility;
>>      unsigned long flags;
>>  
>>      vcpu->guest_debug = dbg->control;
>> @@ -1017,9 +1018,14 @@ static int set_guest_debug(struct kvm_vcpu
>> *vcpu, struct kvm_guest_debug *dbg)
>>          vcpu->guest_debug = 0;
>>  
>>      flags = vmcs_readl(GUEST_RFLAGS);
>> -    if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
>> +    if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
>>          flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
>> -    else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
>> +        /* We must be interruptible when single-stepping */
>> +        interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
>> +        if (interruptibility & 3)
>> +            vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
>> +                     interruptibility & ~3);
>>   
> 
> Could just write unconditionally - it's not like the write has any
> effect on speed.  vmcs_clear_bits() will do it cleanly.
> 
> But I'm worried about correctness.  Suppose we're singlestepping a sti;
> hlt sequence.  While we'll clear interruptibility, probably receive the
> debug trap (since that's a high priority exception), but then inject the
> interrupt before the hlt, hanging the guest.  So we probably need to
> restore interruptibility on exit.
> 

There was some issue with the original patch, but I think I have a safe
version now that also works as good as the old one. Please see below,
including comments. I'm still open to further concerns or better
approaches. Sheng, maybe you can provide some more details on how one is
supposed to handle this hairy case with VMX.

> This looks like a good candidate for a test case.
> 

This will be more complicated as I'm currently able to handle: kvmctl
would have to be extended to interact with the guest debug interface of
kvm, setting appropriate breakpoints and handling the callbacks.

Jan

----------->

When single-stepping over STI and MOV SS, we must clear the
corresponding interruptibility bits in the guest state. Otherwise
vmentry fails as it then expects bit 14 (BS) in pending debug exceptions
being set, but that's not correct for the guest debugging case.

Note that clearing those bits is safe as we check for interruptibility
based on the original state and do not inject interrupts or NMIs if
guest interruptibility was blocked.

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

 arch/x86/kvm/vmx.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ec37635..26f732c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2477,6 +2477,11 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
 {
 	vmx_update_window_states(vcpu);
 
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+		vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
+				GUEST_INTR_STATE_STI |
+				GUEST_INTR_STATE_MOV_SS);
+
 	if (vcpu->arch.nmi_pending && !vcpu->arch.nmi_injected) {
 		if (vcpu->arch.interrupt.pending) {
 			enable_nmi_window(vcpu);
@@ -3263,6 +3268,11 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
 
 	vmx_update_window_states(vcpu);
 
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+		vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
+				GUEST_INTR_STATE_STI |
+				GUEST_INTR_STATE_MOV_SS);
+
 	if (vcpu->arch.nmi_pending && !vcpu->arch.nmi_injected) {
 		if (vcpu->arch.interrupt.pending) {
 			enable_nmi_window(vcpu);

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

end of thread, other threads:[~2008-12-11 19:17 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-27 11:43 [PATCH 0/5] KVM: Improved guest debugging / debug register emulation Jan Kiszka
2008-11-27 11:43 ` [PATCH 5/5] KVM: x86: Wire-up hardware breakpoints for guest debugging Jan Kiszka
2008-11-27 11:43 ` [PATCH 3/5] KVM: VMX: Ensure interruptibility when single-stepping Jan Kiszka
2008-12-07 10:05   ` Avi Kivity
2008-12-08  9:17     ` Jan Kiszka
2008-12-11 19:15     ` [PATCH] KVM: VMX: Allow single-stepping when interruptible Jan Kiszka
2008-11-27 11:43 ` [PATCH 1/5] VMX: Support for injecting software exceptions Jan Kiszka
2008-11-27 11:43 ` [PATCH 2/5] KVM: New guest debug interface Jan Kiszka
2008-12-07  9:55   ` Avi Kivity
2008-12-08  9:13     ` Jan Kiszka
2008-12-08  9:34       ` Avi Kivity
2008-12-08  9:42         ` Jan Kiszka
2008-12-08 13:47         ` Jan Kiszka
2008-12-08 14:57           ` Avi Kivity
2008-12-08 15:17             ` Jan Kiszka
2008-12-10  8:48               ` Avi Kivity
2008-11-27 11:43 ` [PATCH 4/5] KVM: x86: Virtualize debug registers Jan Kiszka
  -- strict thread matches above, loose matches on Subject: below --
2008-10-06  9:15 [PATCH 0/5] KVM: Fix and improve guest debugging and x86 " Jan Kiszka
2008-10-06  9:15 ` [PATCH 3/5] KVM: VMX: Ensure interruptibility when single-stepping 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).