This add-on patch to recent guest debugging refactorings adds the requested awareness for KVM_CAP_X86_ROBUST_SINGLESTEP to both the upstream as well as qemu-kvm's own code. Fortunately, code sharing increased once again. Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxxxxxxx> --- kvm-all.c | 12 ++++++++++ kvm.h | 1 + qemu-kvm-x86.c | 27 +---------------------- qemu-kvm.h | 1 + target-i386/kvm.c | 60 ++++++++++++++++++++++++++++++---------------------- 5 files changed, 51 insertions(+), 50 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index d1542e3..06708a5 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -65,6 +65,7 @@ struct KVMState int broken_set_mem_region; int migration_log; int vcpu_events; + int robust_singlestep; #ifdef KVM_CAP_SET_GUEST_DEBUG struct kvm_sw_breakpoint_head kvm_sw_breakpoints; #endif @@ -673,6 +674,12 @@ int kvm_init(int smp_cpus) s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS); #endif + s->robust_singlestep = 0; +#ifdef KVM_CAP_X86_ROBUST_SINGLESTEP + s->robust_singlestep = + kvm_check_extension(s, KVM_CAP_X86_ROBUST_SINGLESTEP); +#endif + ret = kvm_arch_init(s, smp_cpus); if (ret < 0) goto err; @@ -933,6 +940,11 @@ int kvm_has_vcpu_events(void) return kvm_state->vcpu_events; } +int kvm_has_robust_singlestep(void) +{ + return kvm_state->robust_singlestep; +} + void kvm_setup_guest_memory(void *start, size_t size) { if (!kvm_has_sync_mmu()) { diff --git a/kvm.h b/kvm.h index 1b498d7..888dfcb 100644 --- a/kvm.h +++ b/kvm.h @@ -43,6 +43,7 @@ int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size); int kvm_has_sync_mmu(void); int kvm_has_vcpu_events(void); +int kvm_has_robust_singlestep(void); int kvm_put_vcpu_events(CPUState *env); int kvm_get_vcpu_events(CPUState *env); diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index 5af9ce1..5db95f8 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -922,31 +922,8 @@ void kvm_arch_load_regs(CPUState *env) 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"); - } - } + /* must be last */ + kvm_guest_debug_workarounds(env); } void kvm_load_tsc(CPUState *env) diff --git a/qemu-kvm.h b/qemu-kvm.h index ecb52c1..ed00665 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -1012,6 +1012,7 @@ struct KVMState { int broken_set_mem_region; int migration_log; int vcpu_events; + int robust_singlestep; #ifdef KVM_CAP_SET_GUEST_DEBUG QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints; #endif diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 4e1358c..dd636f1 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -861,6 +861,37 @@ int kvm_get_vcpu_events(CPUState *env) return 0; } +static int kvm_guest_debug_workarounds(CPUState *env) +{ + int ret = 0; +#ifdef KVM_CAP_SET_GUEST_DEBUG + unsigned long reinject_trap = 0; + + if (!kvm_has_vcpu_events()) { + 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; + } + + /* + * Kernels before KVM_CAP_X86_ROBUST_SINGLESTEP 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 (reinject_trap || + (!kvm_has_robust_singlestep() && env->singlestep_enabled)) { + ret = kvm_update_guest_debug(env, reinject_trap); + } +#endif /* KVM_CAP_SET_GUEST_DEBUG */ + return ret; +} + #ifdef KVM_UPSTREAM int kvm_arch_put_registers(CPUState *env) { @@ -890,31 +921,10 @@ int kvm_arch_put_registers(CPUState *env) if (ret < 0) return ret; - /* - * 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; - - ret = kvm_update_guest_debug(env, reinject_trap); - if (ret < 0) { - return ret; - } - } + /* must be last */ + ret = kvm_guest_debug_workarounds(env); + if (ret < 0) + return ret; return 0; } -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html