* [PATCH 0/3] Rework guest debug interface
@ 2008-05-23 1:50 Jan Kiszka
2008-05-23 1:57 ` [PATCH 1/3] KVM: Rework guest debugging interface Jan Kiszka
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Jan Kiszka @ 2008-05-23 1:50 UTC (permalink / raw)
To: Jan Kiszka
[-- Attachment #1: Type: text/plain, Size: 1341 bytes --]
The existing guest debugging interface of kvm is limited in several ways:
- depends on hardware breakpoints, thus suffers from running out of
this scarce resource.
- assumes that there are only 4 hardware breakpoints (even if some
archs may once provide more)
- doesn't support watchpoint or additional arch-specific debugging
features
This patch series reworks the interface, providing usable software-based
breakpoint support, but also laying the ground for patches under
development that will add full hardware debugging features.
Content:
Patch 1 - Replace KVM_DEBUG_GUEST with KVM_SET_GUEST_DEBUG interface,
implement kernel side support
Patch 2 - Tiny helper that allows pause and resume for a single vcpu
Patch 3 - Userland changes that adopt KVM_SET_GUEST_DEBUG and switch to
software breakpoints
Depends on:
- "Fix monitor and gdbstub deadlocks v2" [1]
- "Proper vm_stop on debug events" [2]
It's late here and the series is still fresh, but everything seems to
works nicely - even using gdb inside the guest while the host has active
breakpoints on the guest as well.
Looking forward to feedback and review.
Jan
[1] http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/17444
[2] http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/17775
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 254 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] KVM: Rework guest debugging interface
2008-05-23 1:50 [PATCH 0/3] Rework guest debug interface Jan Kiszka
@ 2008-05-23 1:57 ` Jan Kiszka
2008-05-23 1:59 ` [PATCH 2/3] qemu-kvm: Introduce single vcpu pause/resume Jan Kiszka
2008-05-23 2:01 ` [PATCH 3/3] kvm-userspace: Switch to KVM_SET_GUEST_DEBUG Jan Kiszka
2 siblings, 0 replies; 5+ messages in thread
From: Jan Kiszka @ 2008-05-23 1:57 UTC (permalink / raw)
To: kvm-devel
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 is not
interested. Moreover, it lays the ground for full hardware debug
register / watchpoint support.
To signal breakpoint events properly back to userland, the current PC as
well as an arch-specific data block is now returned along
KVM_EXIT_DEBUG. For x86, the arch block contains the debug exception and
relevant debug registers to tell possible debug events apart.
The availability of the new interface is signaled by
KVM_CAP_SET_GUEST_DEBUG.
Note that both svm and vtx are supported, but only the latter was tested
yet.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
arch/ia64/kvm/kvm-ia64.c | 4 +-
arch/powerpc/kvm/powerpc.c | 4 +-
arch/s390/kvm/kvm-s390.c | 4 +-
arch/x86/kvm/svm.c | 45 +++++++++++++++++++++++-
arch/x86/kvm/vmx.c | 83 ++++++++++++++-------------------------------
arch/x86/kvm/x86.c | 17 ++++-----
include/asm-ia64/kvm.h | 7 +++
include/asm-powerpc/kvm.h | 7 +++
include/asm-s390/kvm.h | 7 +++
include/asm-x86/kvm.h | 17 +++++++++
include/asm-x86/kvm_host.h | 11 +----
include/linux/kvm.h | 52 +++++++++++++++++++---------
include/linux/kvm_host.h | 6 +--
virt/kvm/kvm_main.c | 6 +--
14 files changed, 168 insertions(+), 102 deletions(-)
Index: b/arch/x86/kvm/x86.c
===================================================================
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2730,10 +2730,6 @@ static int __vcpu_run(struct kvm_vcpu *v
down_read(&vcpu->kvm->slots_lock);
vapic_enter(vcpu);
-preempted:
- if (vcpu->guest_debug.enabled)
- kvm_x86_ops->guest_debug_pre(vcpu);
-
again:
if (vcpu->requests)
if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
@@ -2869,7 +2865,7 @@ out:
if (r > 0) {
kvm_resched(vcpu);
down_read(&vcpu->kvm->slots_lock);
- goto preempted;
+ goto again;
}
post_kvm_run_save(vcpu, kvm_run);
@@ -2973,7 +2969,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct
/*
* 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);
@@ -3589,8 +3585,8 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct
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;
@@ -3598,6 +3594,11 @@ int kvm_arch_vcpu_ioctl_debug_guest(stru
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;
Index: b/include/asm-x86/kvm.h
===================================================================
--- a/include/asm-x86/kvm.h
+++ b/include/asm-x86/kvm.h
@@ -230,4 +230,21 @@ struct kvm_pit_state {
#define KVM_TRC_APIC_ACCESS (KVM_TRC_HANDLER + 0x14)
#define KVM_TRC_TDP_FAULT (KVM_TRC_HANDLER + 0x15)
+struct kvm_debug_exit_arch {
+ __u32 exception;
+ __u32 pad;
+ __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];
+};
+
#endif
Index: b/include/asm-x86/kvm_host.h
===================================================================
--- a/include/asm-x86/kvm_host.h
+++ b/include/asm-x86/kvm_host.h
@@ -54,6 +54,8 @@
#define KVM_PAGES_PER_HPAGE (KVM_HPAGE_SIZE / PAGE_SIZE)
#define DE_VECTOR 0
+#define DB_VECTOR 1
+#define BP_VECTOR 3
#define UD_VECTOR 6
#define NM_VECTOR 7
#define DF_VECTOR 8
@@ -122,12 +124,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.
@@ -383,8 +379,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);
Index: b/include/linux/kvm.h
===================================================================
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -125,6 +125,8 @@ struct kvm_run {
__u64 data_offset; /* relative to kvm_run start */
} io;
struct {
+ __u64 pc;
+ struct kvm_debug_exit_arch arch;
} debug;
/* KVM_EXIT_MMIO */
struct {
@@ -192,21 +194,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;
@@ -267,6 +254,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
@@ -346,6 +344,7 @@ struct kvm_trace_rec {
#define KVM_CAP_NOP_IO_DELAY 12
#define KVM_CAP_PV_MMU 13
#define KVM_CAP_MP_STATE 14
+#define KVM_CAP_SET_GUEST_DEBUG 15
/*
* ioctls for VM fds
@@ -382,7 +381,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)
@@ -409,5 +409,25 @@ struct kvm_trace_rec {
#define KVM_S390_INITIAL_RESET _IO(KVMIO, 0x97)
#define KVM_GET_MP_STATE _IOR(KVMIO, 0x98, struct kvm_mp_state)
#define KVM_SET_MP_STATE _IOW(KVMIO, 0x99, struct kvm_mp_state)
+/* 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)
#endif
Index: b/include/linux/kvm_host.h
===================================================================
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -66,7 +66,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;
@@ -237,8 +237,8 @@ int kvm_arch_vcpu_ioctl_get_mpstate(stru
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);
Index: b/arch/x86/kvm/vmx.c
===================================================================
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -465,8 +465,13 @@ static void update_exception_bitmap(stru
eb = (1u << PF_VECTOR) | (1u << UD_VECTOR);
if (!vcpu->fpu_active)
eb |= 1u << NM_VECTOR;
- if (vcpu->guest_debug.enabled)
- eb |= 1u << 1;
+ 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())
@@ -950,40 +955,23 @@ static void vcpu_put_rsp_rip(struct kvm_
vmcs_writel(GUEST_RIP, vcpu->arch.rip);
}
-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;
}
@@ -2196,24 +2184,6 @@ static int vmx_set_tss_addr(struct kvm *
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)
{
@@ -2233,7 +2203,7 @@ static int handle_rmode_exception(struct
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;
@@ -2291,14 +2261,16 @@ static int handle_exception(struct kvm_v
return 1;
}
- if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) ==
- (INTR_TYPE_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.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;
}
@@ -3194,7 +3166,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,
Index: b/arch/x86/kvm/svm.c
===================================================================
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -903,9 +903,32 @@ static void svm_set_segment(struct kvm_v
}
-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)
@@ -1017,6 +1040,22 @@ static int pf_interception(struct vcpu_s
return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
}
+static int db_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+{
+ kvm_run->exit_reason = KVM_EXIT_DEBUG;
+ kvm_run->debug.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.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;
@@ -1395,6 +1434,8 @@ static int (*svm_exit_handlers[])(struct
[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,
Index: b/virt/kvm/kvm_main.c
===================================================================
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1042,13 +1042,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;
Index: b/arch/ia64/kvm/kvm-ia64.c
===================================================================
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1299,8 +1299,8 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct k
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;
}
Index: b/arch/powerpc/kvm/powerpc.c
===================================================================
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -240,8 +240,8 @@ void kvm_arch_vcpu_put(struct kvm_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)
{
return -ENOTSUPP;
}
Index: b/arch/s390/kvm/kvm-s390.c
===================================================================
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -401,8 +401,8 @@ int kvm_arch_vcpu_ioctl_translate(struct
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 */
}
Index: b/include/asm-ia64/kvm.h
===================================================================
--- a/include/asm-ia64/kvm.h
+++ b/include/asm-ia64/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
Index: b/include/asm-powerpc/kvm.h
===================================================================
--- a/include/asm-powerpc/kvm.h
+++ b/include/asm-powerpc/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 */
Index: b/include/asm-s390/kvm.h
===================================================================
--- a/include/asm-s390/kvm.h
+++ b/include/asm-s390/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
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/3] qemu-kvm: Introduce single vcpu pause/resume
2008-05-23 1:50 [PATCH 0/3] Rework guest debug interface Jan Kiszka
2008-05-23 1:57 ` [PATCH 1/3] KVM: Rework guest debugging interface Jan Kiszka
@ 2008-05-23 1:59 ` Jan Kiszka
2008-05-23 15:49 ` Jan Kiszka
2008-05-23 2:01 ` [PATCH 3/3] kvm-userspace: Switch to KVM_SET_GUEST_DEBUG Jan Kiszka
2 siblings, 1 reply; 5+ messages in thread
From: Jan Kiszka @ 2008-05-23 1:59 UTC (permalink / raw)
To: kvm-devel
Small helpers that allow to pause and resume only a single vcpu thread.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
qemu/qemu-kvm.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
Index: b/qemu/qemu-kvm.c
===================================================================
--- a/qemu/qemu-kvm.c
+++ b/qemu/qemu-kvm.c
@@ -207,6 +207,17 @@ static int all_threads_paused(void)
return 1;
}
+static void pause_vcpu_thread(int index)
+{
+ assert(cpu_single_env->cpu_index != index);
+
+ vcpu_info[index].stop = 1;
+ pthread_kill(vcpu_info[index].thread, SIG_IPI);
+
+ while (!vcpu_info[index].stopped)
+ qemu_cond_wait(&qemu_pause_cond);
+}
+
static void pause_all_threads(void)
{
int i;
@@ -221,17 +232,21 @@ static void pause_all_threads(void)
qemu_cond_wait(&qemu_pause_cond);
}
+static void resume_vcpu_thread(int index)
+{
+ assert(!cpu_single_env);
+
+ vcpu_info[index].stop = 0;
+ vcpu_info[index].stopped = 0;
+ pthread_kill(vcpu_info[index].thread, SIG_IPI);
+}
+
static void resume_all_threads(void)
{
int i;
- assert(!cpu_single_env);
-
- for (i = 0; i < smp_cpus; ++i) {
- vcpu_info[i].stop = 0;
- vcpu_info[i].stopped = 0;
- pthread_kill(vcpu_info[i].thread, SIG_IPI);
- }
+ for (i = 0; i < smp_cpus; ++i)
+ resume_vcpu_thread(i);
}
static void kvm_vm_state_change_handler(void *context, int running)
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/3] kvm-userspace: Switch to KVM_SET_GUEST_DEBUG
2008-05-23 1:50 [PATCH 0/3] Rework guest debug interface Jan Kiszka
2008-05-23 1:57 ` [PATCH 1/3] KVM: Rework guest debugging interface Jan Kiszka
2008-05-23 1:59 ` [PATCH 2/3] qemu-kvm: Introduce single vcpu pause/resume Jan Kiszka
@ 2008-05-23 2:01 ` Jan Kiszka
2 siblings, 0 replies; 5+ messages in thread
From: Jan Kiszka @ 2008-05-23 2:01 UTC (permalink / raw)
To: kvm-devel
This patch switches both libkvm as well as the qemu pieces over to the
new guest debug interface. This means, instead of relying on hardware
breakpoints, breakpoint traps are patched into the guest code at the
required spots. Breakpoint management is done inside the qemu-kvm,
transparent to gdbstub and also avoiding that the gdb frontend takes
over. This allows for running debuggers inside the guest while guest
debugging it active, because the host can cleanly tell apart host- and
guest-originated breakpoint events.
Yet improvable are x86 corner cases when using single-step ("forgotten"
debug flags on the guest's stack). And, of courese, the yet empty
non-x86 helper functions have to be populated...
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
libkvm/kvm-common.h | 2
libkvm/libkvm-x86.c | 20 ++++++
libkvm/libkvm.c | 11 +--
libkvm/libkvm.h | 14 +++-
qemu/exec.c | 15 ++--
qemu/qemu-kvm-ia64.c | 17 +++++
qemu/qemu-kvm-powerpc.c | 17 +++++
qemu/qemu-kvm-x86.c | 32 +++++++++
qemu/qemu-kvm.c | 154 +++++++++++++++++++++++++++++++++++++++++-------
qemu/qemu-kvm.h | 27 +++++++-
10 files changed, 268 insertions(+), 41 deletions(-)
Index: b/libkvm/kvm-common.h
===================================================================
--- a/libkvm/kvm-common.h
+++ b/libkvm/kvm-common.h
@@ -85,4 +85,6 @@ int handle_io_window(kvm_context_t kvm);
int handle_debug(kvm_context_t kvm, int vcpu);
int try_push_interrupts(kvm_context_t kvm);
+int handle_debug(kvm_context_t kvm, int vcpu);
+
#endif
Index: b/libkvm/libkvm-x86.c
===================================================================
--- a/libkvm/libkvm-x86.c
+++ b/libkvm/libkvm-x86.c
@@ -661,3 +661,23 @@ int kvm_disable_tpr_access_reporting(kvm
}
#endif
+
+int handle_debug(kvm_context_t kvm, int vcpu)
+{
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+ struct kvm_run *run = kvm->run[vcpu];
+ unsigned long watchpoint = 0;
+ int break_type;
+
+ if (run->debug.arch.exception == 1) {
+ /* TODO: fully process run->debug.arch */
+ break_type = KVM_GDB_BREAKPOINT_HW;
+ } else
+ break_type = KVM_GDB_BREAKPOINT_SW;
+
+ return kvm->callbacks->debug(kvm->opaque, vcpu, break_type,
+ run->debug.pc, watchpoint);
+#else
+ return -ENOSYS;
+#endif
+}
Index: b/libkvm/libkvm.c
===================================================================
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -738,11 +738,6 @@ static int handle_io(kvm_context_t kvm,
return 0;
}
-int handle_debug(kvm_context_t kvm, int vcpu)
-{
- return kvm->callbacks->debug(kvm->opaque, vcpu);
-}
-
int kvm_get_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs)
{
return ioctl(kvm->vcpu_fd[vcpu], KVM_GET_REGS, regs);
@@ -945,10 +940,12 @@ int kvm_inject_irq(kvm_context_t kvm, in
return ioctl(kvm->vcpu_fd[vcpu], KVM_INTERRUPT, &intr);
}
-int kvm_guest_debug(kvm_context_t kvm, int vcpu, struct kvm_debug_guest *dbg)
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+int kvm_set_guest_debug(kvm_context_t kvm, int vcpu, struct kvm_guest_debug *dbg)
{
- return ioctl(kvm->vcpu_fd[vcpu], KVM_DEBUG_GUEST, dbg);
+ return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_GUEST_DEBUG, dbg);
}
+#endif
int kvm_set_signal_mask(kvm_context_t kvm, int vcpu, const sigset_t *sigset)
{
Index: b/qemu/exec.c
===================================================================
--- a/qemu/exec.c
+++ b/qemu/exec.c
@@ -1157,6 +1157,9 @@ int cpu_breakpoint_insert(CPUState *env,
#if defined(TARGET_HAS_ICE)
int i;
+ if (kvm_enabled())
+ return kvm_insert_breakpoint(env, pc, len, type);
+
for(i = 0; i < env->nb_breakpoints; i++) {
if (env->breakpoints[i] == pc)
return 0;
@@ -1166,9 +1169,6 @@ int cpu_breakpoint_insert(CPUState *env,
return -ENOBUFS;
env->breakpoints[env->nb_breakpoints++] = pc;
- if (kvm_enabled())
- kvm_update_debugger(env);
-
breakpoint_invalidate(env, pc);
return 0;
#else
@@ -1182,6 +1182,10 @@ int cpu_breakpoint_remove(CPUState *env,
{
#if defined(TARGET_HAS_ICE)
int i;
+
+ if (kvm_enabled())
+ return kvm_remove_breakpoint(env, pc, len, type);
+
for(i = 0; i < env->nb_breakpoints; i++) {
if (env->breakpoints[i] == pc)
goto found;
@@ -1192,9 +1196,6 @@ int cpu_breakpoint_remove(CPUState *env,
if (i < env->nb_breakpoints)
env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
- if (kvm_enabled())
- kvm_update_debugger(env);
-
breakpoint_invalidate(env, pc);
return 0;
#else
@@ -1214,7 +1215,7 @@ void cpu_single_step(CPUState *env, int
tb_flush(env);
}
if (kvm_enabled())
- kvm_update_debugger(env);
+ kvm_update_guest_debug(env, KVM_GDB_BREAKPOINT_NONE);
#endif
}
Index: b/qemu/qemu-kvm.c
===================================================================
--- a/qemu/qemu-kvm.c
+++ b/qemu/qemu-kvm.c
@@ -60,6 +60,20 @@ static int io_thread_sigfd = -1;
static int kvm_debug_stop_requested;
+struct kvm_sw_breakpoint *first_sw_breakpoint;
+
+static struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(target_ulong pc)
+{
+ struct kvm_sw_breakpoint *bp = first_sw_breakpoint;
+
+ while (bp) {
+ if (bp->pc == pc)
+ break;
+ bp = bp->next;
+ }
+ return bp;
+}
+
static inline unsigned long kvm_get_thread_id(void)
{
return syscall(SYS_gettid);
@@ -546,13 +560,28 @@ int kvm_main_loop(void)
return 0;
}
-static int kvm_debug(void *opaque, int vcpu)
+static int kvm_debug(void *opaque, int vcpu, int break_type,
+ uint64_t pc, uint64_t watchpoint_addr)
{
- CPUState *env = cpu_single_env;
+ int handle = 0;
- kvm_debug_stop_requested = 1;
- vcpu_info[vcpu].stopped = 1;
- return 1;
+ switch (break_type) {
+ case KVM_GDB_BREAKPOINT_SW:
+ if (kvm_find_sw_breakpoint(pc))
+ handle = 1;
+ break;
+ case KVM_GDB_BREAKPOINT_HW:
+ if (cpu_single_env->singlestep_enabled)
+ handle = 1;
+ break;
+ }
+ if (handle) {
+ kvm_debug_stop_requested = 1;
+ vcpu_info[vcpu].stopped = 1;
+ } else
+ kvm_update_guest_debug(cpu_single_env, break_type);
+
+ return handle;
}
static int kvm_inb(void *opaque, uint16_t addr, uint8_t *data)
@@ -767,28 +796,109 @@ int kvm_qemu_init_env(CPUState *cenv)
return kvm_arch_qemu_init_env(cenv);
}
-int kvm_update_debugger(CPUState *env)
+int kvm_update_guest_debug(CPUState *env, int reinject_trap)
{
- struct kvm_debug_guest dbg;
- int i, r;
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+ struct kvm_guest_debug dbg;
+ int err;
- dbg.enabled = 0;
- if (env->nb_breakpoints || env->singlestep_enabled) {
- dbg.enabled = 1;
- for (i = 0; i < 4 && i < env->nb_breakpoints; ++i) {
- dbg.breakpoints[i].enabled = 1;
- dbg.breakpoints[i].address = env->breakpoints[i];
- }
- dbg.singlestep = env->singlestep_enabled;
+ dbg.control = 0;
+ if (env->singlestep_enabled)
+ dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+
+ kvm_arch_update_guest_debug(env, &dbg, reinject_trap);
+
+ assert(!cpu_single_env || cpu_single_env == env);
+
+ if (!cpu_single_env && vm_running) {
+ pause_vcpu_thread(env->cpu_index);
+ err = kvm_set_guest_debug(kvm_context, env->cpu_index, &dbg);
+ resume_vcpu_thread(env->cpu_index);
+ } else
+ err = kvm_set_guest_debug(kvm_context, env->cpu_index, &dbg);
+ return err;
+#else
+ return -EINVAL;
+#endif
+}
+
+int kvm_insert_breakpoint(CPUState *env, target_ulong pc,
+ target_ulong len, int type)
+{
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+ struct kvm_sw_breakpoint *bp;
+ int err;
+
+ if (type != GDB_BREAKPOINT_SW)
+ return -ENOSYS;
+
+ bp = kvm_find_sw_breakpoint(pc);
+ if (bp) {
+ bp->usecount++;
+ return 0;
}
- if (vm_running)
- pause_all_threads();
- r = kvm_guest_debug(kvm_context, env->cpu_index, &dbg);
- if (vm_running)
- resume_all_threads();
- return r;
+
+ bp = malloc(sizeof(struct kvm_sw_breakpoint));
+ if (!bp)
+ return -ENOMEM;
+
+ bp->pc = pc;
+ bp->usecount = 1;
+ bp->prev = NULL;
+ bp->next = first_sw_breakpoint;
+ err = kvm_arch_insert_sw_breakpoint(env, bp);
+ if (err) {
+ free(bp);
+ return err;
+ }
+
+ first_sw_breakpoint = bp;
+ if (bp->next)
+ bp->next->prev = bp;
+
+ return kvm_update_guest_debug(env, KVM_GDB_BREAKPOINT_NONE);
+#else
+ return -EINVAL;
+#endif
}
+int kvm_remove_breakpoint(CPUState *env, target_ulong pc,
+ target_ulong len, int type)
+{
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+ struct kvm_sw_breakpoint *bp;
+ int err;
+
+ if (type != GDB_BREAKPOINT_SW)
+ return -ENOSYS;
+
+ bp = kvm_find_sw_breakpoint(pc);
+ if (!bp)
+ return -ENOENT;
+
+ if (bp->usecount > 1) {
+ bp->usecount--;
+ return 0;
+ }
+
+ err = kvm_arch_remove_sw_breakpoint(env, bp);
+ if (err)
+ return err;
+
+ if (bp->prev)
+ bp->prev->next = bp->next;
+ else
+ first_sw_breakpoint = bp->next;
+ if (bp->next)
+ bp->next->prev = bp->prev;
+
+ free(bp);
+
+ return kvm_update_guest_debug(env, KVM_GDB_BREAKPOINT_NONE);
+#else
+ return -EINVAL;
+#endif
+}
/*
* dirty pages logging
Index: b/libkvm/libkvm.h
===================================================================
--- a/libkvm/libkvm.h
+++ b/libkvm/libkvm.h
@@ -25,6 +25,13 @@ int kvm_get_msrs(kvm_context_t, int vcpu
int kvm_set_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
#endif
+#define KVM_GDB_BREAKPOINT_NONE (-1)
+#define KVM_GDB_BREAKPOINT_SW 0
+#define KVM_GDB_BREAKPOINT_HW 1
+#define KVM_GDB_WATCHPOINT_WRITE 2
+#define KVM_GDB_WATCHPOINT_READ 3
+#define KVM_GDB_WATCHPOINT_ACCESS 4
+
/*!
* \brief KVM callbacks structure
*
@@ -51,7 +58,8 @@ struct kvm_callbacks {
/// generic memory writes to unmapped memory (For MMIO devices)
int (*mmio_write)(void *opaque, uint64_t addr, uint8_t *data,
int len);
- int (*debug)(void *opaque, int vcpu);
+ int (*debug)(void *opaque, int vcpu, int break_type, uint64_t pc,
+ uint64_t watchpoint);
/*!
* \brief Called when the VCPU issues an 'hlt' instruction.
*
@@ -337,7 +345,9 @@ static inline int kvm_reset_mpstate(kvm_
*/
int kvm_inject_irq(kvm_context_t kvm, int vcpu, unsigned irq);
-int kvm_guest_debug(kvm_context_t, int vcpu, struct kvm_debug_guest *dbg);
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+int kvm_set_guest_debug(kvm_context_t, int vcpu, struct kvm_guest_debug *dbg);
+#endif
#if defined(__i386__) || defined(__x86_64__)
/*!
Index: b/qemu/qemu-kvm.h
===================================================================
--- a/qemu/qemu-kvm.h
+++ b/qemu/qemu-kvm.h
@@ -12,8 +12,6 @@
#include <signal.h>
-#include <signal.h>
-
int kvm_main_loop(void);
int kvm_qemu_init(void);
int kvm_qemu_create_context(void);
@@ -25,7 +23,11 @@ void kvm_save_registers(CPUState *env);
void kvm_load_mpstate(CPUState *env);
void kvm_save_mpstate(CPUState *env);
int kvm_cpu_exec(CPUState *env);
-int kvm_update_debugger(CPUState *env);
+int kvm_insert_breakpoint(CPUState *env, target_ulong pc,
+ target_ulong len, int type);
+int kvm_remove_breakpoint(CPUState *env, target_ulong pc,
+ target_ulong len, int type);
+int kvm_update_guest_debug(CPUState *env, int reinject_trap);
int kvm_qemu_init_env(CPUState *env);
int kvm_qemu_check_extension(int ext);
void kvm_apic_init(CPUState *env);
@@ -61,6 +63,25 @@ int kvm_arch_try_push_interrupts(void *o
void kvm_arch_update_regs_for_sipi(CPUState *env);
void kvm_arch_cpu_reset(CPUState *env);
+struct kvm_guest_debug;
+
+struct kvm_sw_breakpoint {
+ target_ulong pc;
+ target_ulong saved_insn;
+ int usecount;
+ struct kvm_sw_breakpoint *prev;
+ struct kvm_sw_breakpoint *next;
+};
+
+extern struct kvm_sw_breakpoint *first_sw_breakpoint;
+
+int kvm_arch_insert_sw_breakpoint(CPUState *env,
+ struct kvm_sw_breakpoint *bp);
+int kvm_arch_remove_sw_breakpoint(CPUState *env,
+ struct kvm_sw_breakpoint *bp);
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg,
+ int reinject_trap);
+
CPUState *qemu_kvm_cpu_env(int index);
void qemu_kvm_aio_wait_start(void);
Index: b/qemu/qemu-kvm-ia64.c
===================================================================
--- a/qemu/qemu-kvm-ia64.c
+++ b/qemu/qemu-kvm-ia64.c
@@ -65,3 +65,20 @@ void kvm_arch_update_regs_for_sipi(CPUSt
void kvm_arch_cpu_reset(CPUState *env)
{
}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *env,
+ struct kvm_sw_breakpoint *bp)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *env,
+ struct kvm_sw_breakpoint *bp)
+{
+ return -EINVAL;
+}
+
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg,
+ int reinject_type)
+{
+}
Index: b/qemu/qemu-kvm-powerpc.c
===================================================================
--- a/qemu/qemu-kvm-powerpc.c
+++ b/qemu/qemu-kvm-powerpc.c
@@ -217,3 +217,20 @@ int handle_powerpc_dcr_write(int vcpu, u
void kvm_arch_cpu_reset(CPUState *env)
{
}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *env,
+ struct kvm_sw_breakpoint *bp)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *env,
+ struct kvm_sw_breakpoint *bp)
+{
+ return -EINVAL;
+}
+
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg,
+ int reinject_type)
+{
+}
Index: b/qemu/qemu-kvm-x86.c
===================================================================
--- a/qemu/qemu-kvm-x86.c
+++ b/qemu/qemu-kvm-x86.c
@@ -687,3 +687,35 @@ void kvm_arch_cpu_reset(CPUState *env)
}
}
}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *env,
+ struct kvm_sw_breakpoint *bp)
+{
+ uint8_t int3 = 0xcc;
+
+ if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 0) ||
+ cpu_memory_rw_debug(env, bp->pc, &int3, 1, 1))
+ return -EINVAL;
+ return 0;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *env,
+ struct kvm_sw_breakpoint *bp)
+{
+ if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1))
+ return -EINVAL;
+ return 0;
+}
+
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg,
+ int reinject_type)
+{
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+ if (first_sw_breakpoint)
+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+ if (reinject_type == KVM_GDB_BREAKPOINT_HW)
+ dbg->control |= KVM_GUESTDBG_INJECT_DB;
+ else if (reinject_type == KVM_GDB_BREAKPOINT_SW)
+ dbg->control |= KVM_GUESTDBG_INJECT_BP;
+#endif
+}
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/3] qemu-kvm: Introduce single vcpu pause/resume
2008-05-23 1:59 ` [PATCH 2/3] qemu-kvm: Introduce single vcpu pause/resume Jan Kiszka
@ 2008-05-23 15:49 ` Jan Kiszka
0 siblings, 0 replies; 5+ messages in thread
From: Jan Kiszka @ 2008-05-23 15:49 UTC (permalink / raw)
To: kvm-devel
Jan Kiszka wrote:
> Small helpers that allow to pause and resume only a single vcpu thread.
Updated version with corrected assertions:
------------
Small helpers that allow to pause and resume only a single vcpu thread.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
qemu/qemu-kvm.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
Index: b/qemu/qemu-kvm.c
===================================================================
--- a/qemu/qemu-kvm.c
+++ b/qemu/qemu-kvm.c
@@ -207,6 +207,17 @@ static int all_threads_paused(void)
return 1;
}
+static void pause_vcpu_thread(int index)
+{
+ assert(!cpu_single_env || cpu_single_env->cpu_index != index);
+
+ vcpu_info[index].stop = 1;
+ pthread_kill(vcpu_info[index].thread, SIG_IPI);
+
+ while (!vcpu_info[index].stopped)
+ qemu_cond_wait(&qemu_pause_cond);
+}
+
static void pause_all_threads(void)
{
int i;
@@ -221,17 +232,21 @@ static void pause_all_threads(void)
qemu_cond_wait(&qemu_pause_cond);
}
+static void resume_vcpu_thread(int index)
+{
+ assert(!cpu_single_env || cpu_single_env->cpu_index != index);
+
+ vcpu_info[index].stop = 0;
+ vcpu_info[index].stopped = 0;
+ pthread_kill(vcpu_info[index].thread, SIG_IPI);
+}
+
static void resume_all_threads(void)
{
int i;
- assert(!cpu_single_env);
-
- for (i = 0; i < smp_cpus; ++i) {
- vcpu_info[i].stop = 0;
- vcpu_info[i].stopped = 0;
- pthread_kill(vcpu_info[i].thread, SIG_IPI);
- }
+ for (i = 0; i < smp_cpus; ++i)
+ resume_vcpu_thread(i);
}
static void kvm_vm_state_change_handler(void *context, int running)
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-05-23 15:51 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-23 1:50 [PATCH 0/3] Rework guest debug interface Jan Kiszka
2008-05-23 1:57 ` [PATCH 1/3] KVM: Rework guest debugging interface Jan Kiszka
2008-05-23 1:59 ` [PATCH 2/3] qemu-kvm: Introduce single vcpu pause/resume Jan Kiszka
2008-05-23 15:49 ` Jan Kiszka
2008-05-23 2:01 ` [PATCH 3/3] kvm-userspace: Switch to KVM_SET_GUEST_DEBUG Jan Kiszka
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox