diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2010-02-19 19:22:27 +0100 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-02-21 11:19:53 +0200 |
commit | d256d32d6ef65adaff06514fc58a93e11bebae2b (patch) | |
tree | eedcde74c55632c434383c713402db1d5be7ff58 /qemu-kvm-x86.c | |
parent | 1b6d255f9451fbdca6f567a7d79105972a43753e (diff) |
Use upstream guest debug code
Code was absolute identical except for previous fixes and cleanup in
upstream.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'qemu-kvm-x86.c')
-rw-r--r-- | qemu-kvm-x86.c | 197 |
1 files changed, 26 insertions, 171 deletions
diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index 41e057974..5af9ce145 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) @@ -1373,177 +1399,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) { |