From patchwork Sun Jun 22 21:23:16 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Graf X-Patchwork-Id: 4396811 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 993349F390 for ; Sun, 22 Jun 2014 21:25:22 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BDC1E201DE for ; Sun, 22 Jun 2014 21:25:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B709D2021B for ; Sun, 22 Jun 2014 21:25:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752618AbaFVVZN (ORCPT ); Sun, 22 Jun 2014 17:25:13 -0400 Received: from cantor2.suse.de ([195.135.220.15]:33353 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752136AbaFVVXm (ORCPT ); Sun, 22 Jun 2014 17:23:42 -0400 Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 21BD0AD64; Sun, 22 Jun 2014 21:23:38 +0000 (UTC) From: Alexander Graf To: kvm-ppc@vger.kernel.org Cc: kvm@vger.kernel.org Subject: [PATCH 12/33] KVM: PPC: Emulate critical sections when we hit them Date: Sun, 22 Jun 2014 23:23:16 +0200 Message-Id: <1403472217-22263-13-git-send-email-agraf@suse.de> X-Mailer: git-send-email 1.7.12.4 In-Reply-To: <1403472217-22263-1-git-send-email-agraf@suse.de> References: <1403472217-22263-1-git-send-email-agraf@suse.de> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Usually the idea behind critical sections is that we don't ever trap in them. However, we may not be that lucky always. When we do hit a critical section while an interrupt is pending, we need to make sure we can inject the interrupt right when the critical section is over. To achieve this, we just emulate every single instruction inside the critical section until we're out of it. Note: For new we don't trigger this code path until we properly emulate all the instructions necessary to run Linux guests well again. Signed-off-by: Alexander Graf --- arch/powerpc/include/asm/kvm_ppc.h | 1 + arch/powerpc/kvm/book3s.c | 15 +++++++++++++++ arch/powerpc/kvm/booke.c | 35 +++++++++++++++++++++++++++++++++++ arch/powerpc/kvm/powerpc.c | 23 +++++++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 6f7a4e5..ef97e0b 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -117,6 +117,7 @@ extern int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu, extern void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu); extern void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu); +extern bool kvmppc_crit_inhibited_irq_pending(struct kvm_vcpu *vcpu); extern bool kvmppc_critical_section(struct kvm_vcpu *vcpu); extern int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu); extern int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu); diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index d66d31e06..ab54976 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -192,6 +192,21 @@ void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu) kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL_LEVEL); } +bool kvmppc_crit_inhibited_irq_pending(struct kvm_vcpu *vcpu) +{ + unsigned long *p = &vcpu->arch.pending_exceptions; + + if (!(kvmppc_get_msr(vcpu) & MSR_EE)) + return false; + + if (test_bit(BOOK3S_IRQPRIO_DECREMENTER, p) || + test_bit(BOOK3S_IRQPRIO_EXTERNAL, p) || + test_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, p)) + return true; + + return false; +} + int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) { int deliver = 1; diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index eb00d5d..cbe9832 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -342,6 +342,41 @@ static unsigned long get_guest_epr(struct kvm_vcpu *vcpu) #endif } +bool kvmppc_crit_inhibited_irq_pending(struct kvm_vcpu *vcpu) +{ + unsigned long *p = &vcpu->arch.pending_exceptions; + bool ee = !!(kvmppc_get_msr(vcpu) & MSR_EE); + bool ce = !!(kvmppc_get_msr(vcpu) & MSR_CE); + bool me = !!(kvmppc_get_msr(vcpu) & MSR_ME); + bool de = !!(kvmppc_get_msr(vcpu) & MSR_DE); + + if (ee) { + if (test_bit(BOOKE_IRQPRIO_EXTERNAL, p) || + test_bit(BOOKE_IRQPRIO_DBELL, p)) + return true; + } + + if (ce) { + if (test_bit(BOOKE_IRQPRIO_WATCHDOG, p) || + test_bit(BOOKE_IRQPRIO_CRITICAL, p) || + test_bit(BOOKE_IRQPRIO_DBELL_CRIT, p)) + return true; + } + + if (me) { + if (test_bit(BOOKE_IRQPRIO_MACHINE_CHECK, p)) + return true; + } + + if (de) { + if (test_bit(BOOKE_IRQPRIO_DEBUG, p)) + return true; + } + + return false; +} + + /* Deliver the interrupt of the corresponding priority, if possible. */ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 230b2bc..f2de6f4 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -83,6 +83,20 @@ bool kvmppc_critical_section(struct kvm_vcpu *vcpu) return crit; } +static bool kvmppc_needs_emulation(struct kvm_vcpu *vcpu) +{ + /* XXX disable emulation for now, until we implemented everything */ + if (true) + return false; + + /* We're in a critical section, but an interrupt is pending */ + if (kvmppc_critical_section(vcpu) && + kvmppc_crit_inhibited_irq_pending(vcpu)) + return true; + + return false; +} + /* * Common checks before entering the guest world. Call with interrupts * disabled. @@ -141,6 +155,15 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) continue; } + if (kvmppc_needs_emulation(vcpu)) { + /* Emulate one instruction, then try again */ + local_irq_enable(); + vcpu->arch.last_inst = KVM_INST_FETCH_FAILED; + kvmppc_emulate_any_instruction(vcpu); + hard_irq_disable(); + continue; + } + kvm_guest_enter(); return 1; }