From patchwork Fri Feb 19 18:22:26 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 45868 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id DAE34B7CFF for ; Sat, 20 Feb 2010 05:33:38 +1100 (EST) Received: from localhost ([127.0.0.1]:38869 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NiXcI-0000Gs-5Y for incoming@patchwork.ozlabs.org; Fri, 19 Feb 2010 13:30:18 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NiXUt-0006xx-J3 for qemu-devel@nongnu.org; Fri, 19 Feb 2010 13:22:39 -0500 Received: from [199.232.76.173] (port=44323 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NiXUs-0006xN-F8 for qemu-devel@nongnu.org; Fri, 19 Feb 2010 13:22:38 -0500 Received: from Debian-exim by monty-python.gnu.org with spam-scanned (Exim 4.60) (envelope-from ) id 1NiXUp-00006k-0H for qemu-devel@nongnu.org; Fri, 19 Feb 2010 13:22:38 -0500 Received: from mx20.gnu.org ([199.232.41.8]:41455) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NiXUm-00006C-HG for qemu-devel@nongnu.org; Fri, 19 Feb 2010 13:22:33 -0500 Received: from thoth.sbs.de ([192.35.17.2]) by mx20.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NiXUl-000265-GW for qemu-devel@nongnu.org; Fri, 19 Feb 2010 13:22:31 -0500 Received: from mail3.siemens.de (localhost [127.0.0.1]) by thoth.sbs.de (8.12.11.20060308/8.12.11) with ESMTP id o1JIMTcS007087; Fri, 19 Feb 2010 19:22:29 +0100 Received: from localhost.localdomain (mchn012c.ww002.siemens.net [139.25.109.167] (may be forged)) by mail3.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id o1JIMRGD025400; Fri, 19 Feb 2010 19:22:29 +0100 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Date: Fri, 19 Feb 2010 19:22:26 +0100 Message-Id: <68e0d2c45f24b4c183cc1827902afc46d280d89b.1266603744.git.jan.kiszka@siemens.com> X-Mailer: git-send-email 1.6.0.2 In-Reply-To: References: In-Reply-To: References: X-detected-operating-system: by mx20.gnu.org: GNU/Linux 2.4-2.6 X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) Cc: Anthony Liguori , qemu-devel@nongnu.org, kvm@vger.kernel.org, Gleb Natapov Subject: [Qemu-devel] [PATCH 8/9] KVM: Rework of guest debug state writing X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org So far we synchronized any dirty VCPU state back into the kernel before updating the guest debug state. This was a tribute to a deficite in x86 kernels before 2.6.33. But as this is an arch-dependent issue, it is better handle in the x86 part of KVM and remove the writeback point for generic code. This also avoids overwriting the flushed state later on if user space decides to change some more registers before resuming the guest. We furthermore need to reinject guest exceptions via the appropriate mechanism. That is KVM_SET_GUEST_DEBUG for older kernels and KVM_SET_VCPU_EVENTS for recent ones. Using both mechanisms at the same time will cause state corruptions. Signed-off-by: Jan Kiszka --- kvm-all.c | 12 ++++-------- target-i386/kvm.c | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index 2237239..f0c5cf6 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -994,10 +994,6 @@ static void kvm_invoke_set_guest_debug(void *data) struct kvm_set_guest_debug_data *dbg_data = data; CPUState *env = dbg_data->env; - if (env->kvm_vcpu_dirty) { - kvm_arch_put_registers(env); - env->kvm_vcpu_dirty = 0; - } dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg); } @@ -1005,12 +1001,12 @@ int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap) { struct kvm_set_guest_debug_data data; - data.dbg.control = 0; - if (env->singlestep_enabled) - data.dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; + data.dbg.control = reinject_trap; + if (env->singlestep_enabled) { + data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; + } kvm_arch_update_guest_debug(env, &data.dbg); - data.dbg.control |= reinject_trap; data.env = env; on_vcpu(env, kvm_invoke_set_guest_debug, &data); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 8743f32..a4130d4 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -885,6 +885,32 @@ 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; + } + } + return 0; } @@ -1130,10 +1156,13 @@ int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info) } 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); + if (!handle) { + cpu_synchronize_state(cpu_single_env); + assert(cpu_single_env->exception_injected == -1); + + cpu_single_env->exception_injected = arch_info->exception; + cpu_single_env->has_error_code = 0; + } return handle; }