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> --- Note: Due to missing VCPU events synchronization during runtime in qemu-kvm, exception re-injection is unfortunately now broken (I missed a circular dependency in my series). However, the remaining VCPU state refactoring bits will be posted soon, and they will fix it again. Upstream code is not affected. 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 bed562f..0776bf5 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; @@ -932,6 +939,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 a78a27f..427dad0 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 93b144f..172eba8 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -1027,6 +1027,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 01963e1..cf64c9a 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -853,6 +853,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) { @@ -882,31 +913,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; } -- 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