From patchwork Fri Feb 19 18:22:27 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 80786 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o1JIMxCJ028946 for ; Fri, 19 Feb 2010 18:23:00 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755418Ab0BSSWv (ORCPT ); Fri, 19 Feb 2010 13:22:51 -0500 Received: from goliath.siemens.de ([192.35.17.28]:22354 "EHLO goliath.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755374Ab0BSSWu (ORCPT ); Fri, 19 Feb 2010 13:22:50 -0500 Received: from mail3.siemens.de (localhost [127.0.0.1]) by goliath.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id o1JIMTKJ003833; Fri, 19 Feb 2010 19:22:29 +0100 Received: from localhost.localdomain (mchn012c.ww002.siemens.net [139.25.109.167] (may be forged)) by mail3.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id o1JIMRGE025400; Fri, 19 Feb 2010 19:22:29 +0100 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org, qemu-devel@nongnu.org, Anthony Liguori , Gleb Natapov Subject: [PATCH 9/9] qemu-kvm: Use upstream guest debug code Date: Fri, 19 Feb 2010 19:22:27 +0100 Message-Id: <4d0aaa5fc8f3ff5c11bb6fc51a7c5bbb02a0e167.1266603744.git.jan.kiszka@siemens.com> X-Mailer: git-send-email 1.6.0.2 In-Reply-To: References: In-Reply-To: References: Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Fri, 19 Feb 2010 18:23:00 +0000 (UTC) diff --git a/kvm-all.c b/kvm-all.c index f0c5cf6..bed562f 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -962,7 +962,9 @@ static void on_vcpu(CPUState *env, void (*func)(void *data), void *data) #endif func(data); } -#endif /* KVM_UPSTREAM */ +#else /* !KVM_UPSTREAM */ +static void on_vcpu(CPUState *env, void (*func)(void *data), void *data); +#endif /* !KVM_UPSTREAM */ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env, target_ulong pc) @@ -981,8 +983,6 @@ int kvm_sw_breakpoints_active(CPUState *env) return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints); } -#ifdef KVM_UPSTREAM - struct kvm_set_guest_debug_data { struct kvm_guest_debug dbg; CPUState *env; @@ -1012,7 +1012,6 @@ int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap) on_vcpu(env, kvm_invoke_set_guest_debug, &data); return data.err; } -#endif int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, target_ulong len, int type) diff --git a/kvm.h b/kvm.h index 2f97c64..a78a27f 100644 --- a/kvm.h +++ b/kvm.h @@ -54,14 +54,12 @@ int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); void kvm_flush_coalesced_mmio_buffer(void); -#ifdef KVM_UPSTREAM int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, target_ulong len, int type); int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr, target_ulong len, int type); void kvm_remove_all_breakpoints(CPUState *current_env); int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap); -#endif /* KVM_UPSTREAM */ int kvm_pit_in_kernel(void); int kvm_irqchip_in_kernel(void); @@ -94,7 +92,6 @@ int kvm_arch_init(KVMState *s, int smp_cpus); int kvm_arch_init_vcpu(CPUState *env); void kvm_arch_reset_vcpu(CPUState *env); -#ifdef KVM_UPSTREAM struct kvm_guest_debug; struct kvm_debug_exit_arch; @@ -126,7 +123,6 @@ int kvm_arch_remove_hw_breakpoint(target_ulong addr, void kvm_arch_remove_all_hw_breakpoints(void); void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg); -#endif int kvm_check_extension(KVMState *s, unsigned int extension); diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index 2b36c22..bd3c0ab 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -921,6 +921,32 @@ void kvm_arch_load_regs(CPUState *env) rc = kvm_set_msrs(env, msrs, n); if (rc == -1) perror("kvm_set_msrs FAILED"); + + /* + * Kernels before 2.6.33 (which correlates with !kvm_has_vcpu_events()) + * overwrote flags.TF injected via SET_GUEST_DEBUG while updating GP regs. + * Work around this by updating the debug state once again if + * single-stepping is on. + * Another reason to call kvm_update_guest_debug here is a pending debug + * trap raise by the guest. On kernels without SET_VCPU_EVENTS we have to + * reinject them via SET_GUEST_DEBUG. + */ + if (!kvm_has_vcpu_events() && + (env->exception_injected != -1 || env->singlestep_enabled)) { + unsigned long reinject_trap = 0; + + if (env->exception_injected == 1) { + reinject_trap = KVM_GUESTDBG_INJECT_DB; + } else if (env->exception_injected == 3) { + reinject_trap = KVM_GUESTDBG_INJECT_BP; + } + env->exception_injected = -1; + + rc = kvm_update_guest_debug(env, reinject_trap); + if (rc < 0) { + perror("kvm_update_guest_debug FAILED"); + } + } } void kvm_load_tsc(CPUState *env) @@ -1376,177 +1402,6 @@ 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) -{ - uint8_t int3; - - if (cpu_memory_rw_debug(env, bp->pc, &int3, 1, 0) || int3 != 0xcc || - cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) - return -EINVAL; - return 0; -} - -#ifdef KVM_CAP_SET_GUEST_DEBUG -static struct { - target_ulong addr; - int len; - int type; -} hw_breakpoint[4]; - -static int nb_hw_breakpoint; - -static int find_hw_breakpoint(target_ulong addr, int len, int type) -{ - int n; - - for (n = 0; n < nb_hw_breakpoint; n++) - if (hw_breakpoint[n].addr == addr && hw_breakpoint[n].type == type && - (hw_breakpoint[n].len == len || len == -1)) - return n; - return -1; -} - -int kvm_arch_insert_hw_breakpoint(target_ulong addr, - target_ulong len, int type) -{ - switch (type) { - case GDB_BREAKPOINT_HW: - len = 1; - break; - case GDB_WATCHPOINT_WRITE: - case GDB_WATCHPOINT_ACCESS: - switch (len) { - case 1: - break; - case 2: - case 4: - case 8: - if (addr & (len - 1)) - return -EINVAL; - break; - default: - return -EINVAL; - } - break; - default: - return -ENOSYS; - } - - if (nb_hw_breakpoint == 4) - return -ENOBUFS; - - if (find_hw_breakpoint(addr, len, type) >= 0) - return -EEXIST; - - hw_breakpoint[nb_hw_breakpoint].addr = addr; - hw_breakpoint[nb_hw_breakpoint].len = len; - hw_breakpoint[nb_hw_breakpoint].type = type; - nb_hw_breakpoint++; - - return 0; -} - -int kvm_arch_remove_hw_breakpoint(target_ulong addr, - target_ulong len, int type) -{ - int n; - - n = find_hw_breakpoint(addr, (type == GDB_BREAKPOINT_HW) ? 1 : len, type); - if (n < 0) - return -ENOENT; - - nb_hw_breakpoint--; - hw_breakpoint[n] = hw_breakpoint[nb_hw_breakpoint]; - - return 0; -} - -void kvm_arch_remove_all_hw_breakpoints(void) -{ - nb_hw_breakpoint = 0; -} - -static CPUWatchpoint hw_watchpoint; - -int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info) -{ - int handle = 0; - int n; - - if (arch_info->exception == 1) { - if (arch_info->dr6 & (1 << 14)) { - if (cpu_single_env->singlestep_enabled) - handle = 1; - } else { - for (n = 0; n < 4; n++) - if (arch_info->dr6 & (1 << n)) - switch ((arch_info->dr7 >> (16 + n*4)) & 0x3) { - case 0x0: - handle = 1; - break; - case 0x1: - handle = 1; - cpu_single_env->watchpoint_hit = &hw_watchpoint; - hw_watchpoint.vaddr = hw_breakpoint[n].addr; - hw_watchpoint.flags = BP_MEM_WRITE; - break; - case 0x3: - handle = 1; - cpu_single_env->watchpoint_hit = &hw_watchpoint; - hw_watchpoint.vaddr = hw_breakpoint[n].addr; - hw_watchpoint.flags = BP_MEM_ACCESS; - break; - } - } - } else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc)) - handle = 1; - - if (!handle) - kvm_update_guest_debug(cpu_single_env, - (arch_info->exception == 1) ? - KVM_GUESTDBG_INJECT_DB : KVM_GUESTDBG_INJECT_BP); - - return handle; -} - -void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg) -{ - const uint8_t type_code[] = { - [GDB_BREAKPOINT_HW] = 0x0, - [GDB_WATCHPOINT_WRITE] = 0x1, - [GDB_WATCHPOINT_ACCESS] = 0x3 - }; - const uint8_t len_code[] = { - [1] = 0x0, [2] = 0x1, [4] = 0x3, [8] = 0x2 - }; - int n; - - if (kvm_sw_breakpoints_active(env)) - dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; - - if (nb_hw_breakpoint > 0) { - dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; - dbg->arch.debugreg[7] = 0x0600; - for (n = 0; n < nb_hw_breakpoint; n++) { - dbg->arch.debugreg[n] = hw_breakpoint[n].addr; - dbg->arch.debugreg[7] |= (2 << (n * 2)) | - (type_code[hw_breakpoint[n].type] << (16 + n*4)) | - (len_code[hw_breakpoint[n].len] << (18 + n*4)); - } - } -} -#endif - #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT void kvm_arch_do_ioperm(void *_data) { diff --git a/qemu-kvm.c b/qemu-kvm.c index 9821fc5..3a169fc 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -1025,13 +1025,6 @@ int kvm_inject_irq(CPUState *env, unsigned irq) return kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr); } -#ifdef KVM_CAP_SET_GUEST_DEBUG -int kvm_set_guest_debug(CPUState *env, struct kvm_guest_debug *dbg) -{ - return kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, dbg); -} -#endif - int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset) { struct kvm_signal_mask *sigmask; @@ -2312,43 +2305,6 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, return; } -#ifdef KVM_CAP_SET_GUEST_DEBUG - -struct kvm_set_guest_debug_data { - struct kvm_guest_debug dbg; - int err; -}; - -static void kvm_invoke_set_guest_debug(void *data) -{ - struct kvm_set_guest_debug_data *dbg_data = data; - - if (cpu_single_env->kvm_vcpu_dirty) { - kvm_arch_save_regs(cpu_single_env); - cpu_single_env->kvm_vcpu_dirty = 0; - } - dbg_data->err = - kvm_set_guest_debug(cpu_single_env, - &dbg_data->dbg); -} - -int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap) -{ - struct kvm_set_guest_debug_data data; - - data.dbg.control = 0; - if (env->singlestep_enabled) - data.dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; - - kvm_arch_update_guest_debug(env, &data.dbg); - data.dbg.control |= reinject_trap; - - on_vcpu(env, kvm_invoke_set_guest_debug, &data); - return data.err; -} - -#endif - /* * dirty pages logging */ diff --git a/qemu-kvm.h b/qemu-kvm.h index 17017c4..93b144f 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -323,10 +323,6 @@ static inline int kvm_reset_mpstate(CPUState *env) */ int kvm_inject_irq(CPUState *env, unsigned irq); -#ifdef KVM_CAP_SET_GUEST_DEBUG -int kvm_set_guest_debug(CPUState *env, struct kvm_guest_debug *dbg); -#endif - #if defined(__i386__) || defined(__x86_64__) /*! * \brief Setup a vcpu's cpuid instruction emulation @@ -880,12 +876,6 @@ int kvm_init_ap(void); int kvm_vcpu_inited(CPUState *env); void kvm_load_mpstate(CPUState *env); void kvm_save_mpstate(CPUState *env); -int kvm_insert_breakpoint(CPUState * current_env, target_ulong addr, - target_ulong len, int type); -int kvm_remove_breakpoint(CPUState * current_env, target_ulong addr, - target_ulong len, int type); -void kvm_remove_all_breakpoints(CPUState * current_env); -int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap); void kvm_apic_init(CPUState *env); /* called from vcpu initialization */ void qemu_kvm_load_lapic(CPUState *env); @@ -928,33 +918,6 @@ void kvm_arch_push_nmi(void *opaque); void kvm_arch_cpu_reset(CPUState *env); int kvm_set_boot_cpu_id(uint32_t id); -struct kvm_guest_debug; -struct kvm_debug_exit_arch; - -struct kvm_sw_breakpoint { - target_ulong pc; - target_ulong saved_insn; - int use_count; - QTAILQ_ENTRY(kvm_sw_breakpoint) entry; -}; - -QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint); - -int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info); -int kvm_sw_breakpoints_active(CPUState *env); -struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env, - target_ulong pc); -int kvm_arch_insert_sw_breakpoint(CPUState * current_env, - struct kvm_sw_breakpoint *bp); -int kvm_arch_remove_sw_breakpoint(CPUState * current_env, - struct kvm_sw_breakpoint *bp); -int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, - int type); -int kvm_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, - int type); -void kvm_arch_remove_all_hw_breakpoints(void); -void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg); - void qemu_kvm_aio_wait_start(void); void qemu_kvm_aio_wait(void); void qemu_kvm_aio_wait_end(void); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index a4130d4..9e88932 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1020,6 +1020,7 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run) return ret; } +#endif #ifdef KVM_CAP_SET_GUEST_DEBUG int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) @@ -1194,6 +1195,5 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg) } } #endif /* KVM_CAP_SET_GUEST_DEBUG */ -#endif #include "qemu-kvm-x86.c"