From patchwork Tue Mar 19 15:51:13 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 2301901 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id B1427DFB79 for ; Tue, 19 Mar 2013 15:51:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932530Ab3CSPvc (ORCPT ); Tue, 19 Mar 2013 11:51:32 -0400 Received: from mail-wg0-f48.google.com ([74.125.82.48]:61491 "EHLO mail-wg0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756730Ab3CSPvb (ORCPT ); Tue, 19 Mar 2013 11:51:31 -0400 Received: by mail-wg0-f48.google.com with SMTP id 16so488129wgi.3 for ; Tue, 19 Mar 2013 08:51:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:sender:from:to:cc:subject:date:message-id:x-mailer; bh=pBkxA94roEG4bQ9S95ewuSicOFAkHpPM3u9rjSSnbXc=; b=JDiIorsRDS36Gt93qSFeiyyx5tPOKixgdnOp0NiJ+aoyzS/QT4oQ3IihJ5X/98Ugp1 AWy7SBu82o86qnTONDQ5usiA9IRN2kJ2QYruapbR4gVBGfReF1QsBgsM0t/KZLXL7i8g JECbMCYSGg/9IJGj3OXmF/UZcykIUDPo9VUdsJmiq5oU0zwpYZ4rjXwBq14HkMM5P5sF HtEDS7yIOYWb1ri4VEt1puSANYK/LazUNoJeeAoCKyygDozuAKj+xN4RNWtYbPf4/mts Gg7r1mpM8R8cT53v8kGMhyg7CXQQDhcWYdHg6PQk3v6QlNliTSNPgQHAMJXBeoBxLjiW grrA== X-Received: by 10.180.105.99 with SMTP id gl3mr4201654wib.22.1363708289858; Tue, 19 Mar 2013 08:51:29 -0700 (PDT) Received: from playground.lan (93-34-176-20.ip50.fastwebnet.it. [93.34.176.20]) by mx.google.com with ESMTPS id j4sm1381312wiz.10.2013.03.19.08.51.26 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 19 Mar 2013 08:51:28 -0700 (PDT) From: Paolo Bonzini To: linux-kernel@vger.kernel.org Cc: kvm@vger.kernel.org Subject: [PATCH] x86: let userspace inject interrupts into the local APIC Date: Tue, 19 Mar 2013 16:51:13 +0100 Message-Id: <1363708273-19653-1-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.1.4 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org There is no way for userspace to inject interrupts into a VCPU's local APIC, which is important in order to inject INITs coming from the chipset. KVM_INTERRUPT is currently disabled when the in-kernel local APIC is used, so we can repurpose it. The shorthand destination field must contain APIC_DEST_SELF, which has a double effect: first, the ICR2 register is not used and the 32-bit field of KVM_INTERRUPT is enough; second, it ensures that the valid range of the irq field is distinct in the userspace-APIC and kernel-APIC cases. Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/api.txt | 13 ++++++++++--- arch/x86/kvm/lapic.c | 20 +++++++++++++++----- arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/x86.c | 6 +++--- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 4237c27..a69706b 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -396,8 +396,8 @@ Type: vcpu ioctl Parameters: struct kvm_interrupt (in) Returns: 0 on success, -1 on error -Queues a hardware interrupt vector to be injected. This is only -useful if in-kernel local APIC or equivalent is not used. +Queues a hardware interrupt vector to be injected into either the VCPU +or into the in-kernel local APIC or equivalent (if in use). /* for KVM_INTERRUPT */ struct kvm_interrupt { @@ -407,7 +407,14 @@ struct kvm_interrupt { X86: -Note 'irq' is an interrupt vector, not an interrupt pin or line. +If the in-kernel local APIC is enabled, 'irq' is sent to the local APIC +as if it were written to the ICR register, except that it is not reflected +into ICR if the guest reads it. The destination (bits 18 and 19) must be +set to APIC_DEST_SELF. + +If the in-kernel local APIC is disabled, 'irq' is an interrupt vector (not +an interrupt pin or line) that is injected synchronously into the VCPU. + PPC: diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index a8e9369..efb67f7 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -826,12 +826,9 @@ void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector) } EXPORT_SYMBOL_GPL(kvm_apic_set_eoi_accelerated); -static void apic_send_ipi(struct kvm_lapic *apic) +static void apic_send_ipi(struct kvm_lapic *apic, u32 icr_low, u32 icr_high) { - u32 icr_low = kvm_apic_get_reg(apic, APIC_ICR); - u32 icr_high = kvm_apic_get_reg(apic, APIC_ICR2); struct kvm_lapic_irq irq; - irq.vector = icr_low & APIC_VECTOR_MASK; irq.delivery_mode = icr_low & APIC_MODE_MASK; irq.dest_mode = icr_low & APIC_DEST_MASK; @@ -855,6 +852,16 @@ static void apic_send_ipi(struct kvm_lapic *apic) kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq); } +int kvm_lapic_ioctl_interrupt(struct kvm_vcpu *vcpu, u32 value) +{ + if ((value & APIC_SHORT_MASK) != APIC_DEST_SELF) + return -EINVAL; + + apic_send_ipi(vcpu->arch.apic, value, 0); + return 0; +} +EXPORT_SYMBOL_GPL(kvm_lapic_ioctl_interrupt); + static u32 apic_get_tmcct(struct kvm_lapic *apic) { ktime_t remaining; @@ -1155,7 +1162,10 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_ICR: /* No delay here, so we always clear the pending bit */ apic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); - apic_send_ipi(apic); + apic_send_ipi(apic, + kvm_apic_get_reg(apic, APIC_ICR), + kvm_apic_get_reg(apic, APIC_ICR2)); + break; case APIC_ICR2: diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 2c721b9..0631b5c 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -49,6 +49,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu); u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu); +int kvm_lapic_ioctl_interrupt(struct kvm_vcpu *vcpu, u32 value); void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); void kvm_apic_set_version(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3e0a8ba..ab4a401 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2703,11 +2703,11 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { - if (irq->irq >= KVM_NR_INTERRUPTS) - return -EINVAL; if (irqchip_in_kernel(vcpu->kvm)) - return -ENXIO; + return kvm_lapic_ioctl_interrupt(vcpu, irq->irq); + if (irq->irq >= KVM_NR_INTERRUPTS) + return -EINVAL; kvm_queue_interrupt(vcpu, irq->irq, false); kvm_make_request(KVM_REQ_EVENT, vcpu);