From patchwork Wed Feb 24 14:17:49 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 81751 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 o1OEMVgb022636 for ; Wed, 24 Feb 2010 14:22:31 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755452Ab0BXOW0 (ORCPT ); Wed, 24 Feb 2010 09:22:26 -0500 Received: from thoth.sbs.de ([192.35.17.2]:17574 "EHLO thoth.sbs.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753605Ab0BXOWZ (ORCPT ); Wed, 24 Feb 2010 09:22:25 -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 o1OEHvgK005060; Wed, 24 Feb 2010 15:17:57 +0100 Received: from localhost.localdomain (mchn012c.ww002.siemens.net [139.25.109.167] (may be forged)) by mail2.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id o1OEHvk0006898; Wed, 24 Feb 2010 15:17:57 +0100 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org, qemu-devel@nongnu.org, Gleb Natapov Subject: [PATCH v3 01/10] qemu-kvm: Add KVM_CAP_X86_ROBUST_SINGLESTEP-awareness Date: Wed, 24 Feb 2010 15:17:49 +0100 Message-Id: <73ac9d5e94b9b11dac31de9ad621deb79e527041.1267021065.git.jan.kiszka@siemens.com> 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]); Wed, 24 Feb 2010 14:22:31 +0000 (UTC) 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; }