From patchwork Tue Feb 2 08:18:59 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 76327 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 o128KHYD032259 for ; Tue, 2 Feb 2010 08:20:17 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755336Ab0BBIUD (ORCPT ); Tue, 2 Feb 2010 03:20:03 -0500 Received: from thoth.sbs.de ([192.35.17.2]:20632 "EHLO thoth.sbs.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754923Ab0BBITp (ORCPT ); Tue, 2 Feb 2010 03:19:45 -0500 Received: from mail2.siemens.de (localhost [127.0.0.1]) by thoth.sbs.de (8.12.11.20060308/8.12.11) with ESMTP id o128JEJV010312; Tue, 2 Feb 2010 09:19:14 +0100 Received: from localhost.localdomain ([139.25.173.39]) by mail2.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id o128J7sT008551; Tue, 2 Feb 2010 09:19:14 +0100 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org, Anthony Liguori , Alexander Graf , Glauber Costa , qemu-devel@nongnu.org Subject: [PATCH 13/21] qemu-kvm: Use upstream guest debug code Date: Tue, 2 Feb 2010 09:18:59 +0100 Message-Id: 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]); Tue, 02 Feb 2010 08:20:17 +0000 (UTC) diff --git a/kvm-all.c b/kvm-all.c index 9c921cc..f3cfa2c 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -919,7 +919,9 @@ static void on_vcpu(CPUState *env, void (*func)(void *data), void *data) func(data); #endif } -#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) @@ -938,8 +940,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; @@ -969,7 +969,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 253b45d..740fd1a 100644 --- a/kvm.h +++ b/kvm.h @@ -61,14 +61,12 @@ void kvm_setup_guest_memory(void *start, size_t size); 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); -#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); @@ -101,7 +99,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; @@ -133,7 +130,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 074b510..834e9c1 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -835,6 +835,13 @@ void kvm_arch_load_regs(CPUState *env) kvm_set_regs(env, ®s); + /* + * Kernels before 2.6.33 overwrote flags.TF injected via SET_GUEST_DEBUG + * while updating GP regs. Work around this by updating the debug state + * once again. + */ + kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &env->kvm_guest_debug); + memset(&fpu, 0, sizeof fpu); fpu.fsw = env->fpus & ~(7 << 11); fpu.fsw |= (env->fpstt & 7) << 11; @@ -1372,177 +1379,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 c04f805..a220353 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -1016,13 +1016,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; @@ -2318,43 +2311,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 4c687ce..e8c3a58 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 5ac12a8..e1ae15d 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1003,6 +1003,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) @@ -1176,6 +1177,5 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg) memcpy(&env->kvm_guest_debug, dbg, sizeof(env->kvm_guest_debug)); } #endif /* KVM_CAP_SET_GUEST_DEBUG */ -#endif #include "qemu-kvm-x86.c"