From patchwork Mon Mar 1 17:17:20 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 83002 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 o21HIKmm025117 for ; Mon, 1 Mar 2010 17:18:20 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751754Ab0CARRy (ORCPT ); Mon, 1 Mar 2010 12:17:54 -0500 Received: from david.siemens.de ([192.35.17.14]:23181 "EHLO david.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751666Ab0CARRx (ORCPT ); Mon, 1 Mar 2010 12:17:53 -0500 Received: from mail2.siemens.de (localhost [127.0.0.1]) by david.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id o21HHUr4020540; Mon, 1 Mar 2010 18:17:30 +0100 Received: from localhost.localdomain (mchn012c.mchp.siemens.de [139.25.109.167] (may be forged)) by mail2.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id o21HHUx0000935; Mon, 1 Mar 2010 18:17:30 +0100 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org, qemu-devel@nongnu.org, Gleb Natapov Subject: [PATCH v4 01/10] qemu-kvm: Add KVM_CAP_X86_ROBUST_SINGLESTEP-awareness Date: Mon, 1 Mar 2010 18:17:20 +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]); Mon, 01 Mar 2010 17:18:20 +0000 (UTC) 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; }