From patchwork Wed Apr 5 23:19:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 9665923 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id F0C8D60364 for ; Wed, 5 Apr 2017 23:23:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E282C2816B for ; Wed, 5 Apr 2017 23:23:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D76D028584; Wed, 5 Apr 2017 23:23:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 474AE2857E for ; Wed, 5 Apr 2017 23:23:31 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cvuEe-0004uH-4k; Wed, 05 Apr 2017 23:21:08 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cvuEc-0004rL-NS for xen-devel@lists.xenproject.org; Wed, 05 Apr 2017 23:21:06 +0000 Received: from [193.109.254.147] by server-5.bemta-6.messagelabs.com id FA/68-27545-2EB75E85; Wed, 05 Apr 2017 23:21:06 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrKLMWRWlGSWpSXmKPExsVysyfVTfdh9dM Ig5s/5Cy+b5nM5MDocfjDFZYAxijWzLyk/IoE1oxFm7+xFmyyqjhz7h5LA+MNnS5GLg4hgU2M EtP/z2OBcPYySiy+c421i5GTg01AV2LHzdfMILaIQKjEnJ+PgGwODmaBSonuRfwgYWEBN4n3P xaDlbAIqEq0zbgH1sor4C7R1TCJHaRcQkBO4sq/BJAwJ1D4ZesxFhBbCKj12sSpLBMYuRcwMq xi1ChOLSpLLdI1NNFLKspMzyjJTczM0TU0MNPLTS0uTkxPzUlMKtZLzs/dxAj0LgMQ7GC8vjH gEKMkB5OSKK+Cz5MIIb6k/JTKjMTijPii0pzU4kOMMhwcShK8fMBgERIsSk1PrUjLzAGGGUxa goNHSYTXqgoozVtckJhbnJkOkTrFqCglzssL0icAksgozYNrg4X2JUZZKWFeRqBDhHgKUotyM 0tQ5V8xinMwKgnzTgEZz5OZVwI3/RXQYiagxU/uPARZXJKIkJJqYJRr/5Sk7cH+sbJh48lNik snlfy81/LxtQlXlWKA4gGZFetenkk9q/Avdrs8T+tJW97v+bu0KmSr/jNzWMRVvuBUmmq/8tn Gx5LRyS9u7dmmv+GEattjEYdNFeFNLbOWO4jvi1F5rSBzJnztdYc77U/VHzRGNy91yb7211y3 VazNeKv8AtcD1UosxRmJhlrMRcWJAK7m75poAgAA X-Env-Sender: andre.przywara@arm.com X-Msg-Ref: server-8.tower-27.messagelabs.com!1491434464!85631312!1 X-Originating-IP: [217.140.101.70] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.4.12; banners=-,-,- X-VirusChecked: Checked Received: (qmail 26726 invoked from network); 5 Apr 2017 23:21:05 -0000 Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by server-8.tower-27.messagelabs.com with SMTP; 5 Apr 2017 23:21:05 -0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A3B4F344; Wed, 5 Apr 2017 16:21:04 -0700 (PDT) Received: from slackpad.lan (usa-sjc-mx-foss1.foss.arm.com [217.140.101.70]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 63E353F4FF; Wed, 5 Apr 2017 16:21:03 -0700 (PDT) From: Andre Przywara To: Stefano Stabellini , Julien Grall Date: Thu, 6 Apr 2017 00:19:10 +0100 Message-Id: <1491434362-30310-19-git-send-email-andre.przywara@arm.com> X-Mailer: git-send-email 2.8.2 In-Reply-To: <1491434362-30310-1-git-send-email-andre.przywara@arm.com> References: <1491434362-30310-1-git-send-email-andre.przywara@arm.com> Cc: xen-devel@lists.xenproject.org, Shanker Donthineni , Vijay Kilari Subject: [Xen-devel] [PATCH v5 18/30] ARM: vITS: introduce translation table walks X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP The ITS stores the target (v)CPU and the (virtual) LPI number in tables. Introduce functions to walk those tables and translate an device ID - event ID pair into a pair of virtual LPI and vCPU. We map those tables on demand - which is cheap on arm64. Also we take care of the locking on the way, since we can't easily protect those ITTs from being altered by the guest. To allow compiling without warnings, we declare two functions as non-static for the moment, which two later patches will fix. Signed-off-by: Andre Przywara --- xen/arch/arm/gic.c | 2 + xen/arch/arm/vgic-v3-its.c | 179 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index a56be34..5000b0d 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -491,6 +491,8 @@ static void gic_update_one_lr(struct vcpu *v, int i) { gic_hw_ops->clear_lr(i); clear_bit(i, &this_cpu(lr_mask)); + if ( is_lpi(irq) ) + clear_bit(GIC_IRQ_GUEST_LPI_PENDING, &p->status); if ( p->desc != NULL ) clear_bit(_IRQ_INPROGRESS, &p->desc->status); diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c index f6bf1ee..a145666 100644 --- a/xen/arch/arm/vgic-v3-its.c +++ b/xen/arch/arm/vgic-v3-its.c @@ -67,6 +67,8 @@ struct vits_itte uint16_t pad; }; +#define UNMAPPED_COLLECTION ((uint16_t)~0) + void vgic_v3_its_init_domain(struct domain *d) { spin_lock_init(&d->arch.vgic.its_devices_lock); @@ -78,6 +80,183 @@ void vgic_v3_its_free_domain(struct domain *d) ASSERT(RB_EMPTY_ROOT(&d->arch.vgic.its_devices)); } +/* + * The physical address is encoded slightly differently depending on + * the used page size: the highest four bits are stored in the lowest + * four bits of the field for 64K pages. + */ +static paddr_t get_baser_phys_addr(uint64_t reg) +{ + if ( reg & BIT(9) ) + return (reg & GENMASK_ULL(47, 16)) | + ((reg & GENMASK_ULL(15, 12)) << 36); + else + return reg & GENMASK_ULL(47, 12); +} + +/* Must be called with the ITS lock held. */ +static struct vcpu *get_vcpu_from_collection(struct virt_its *its, + uint16_t collid) +{ + paddr_t addr = get_baser_phys_addr(its->baser_coll); + uint16_t vcpu_id; + int ret; + + ASSERT(spin_is_locked(&its->its_lock)); + + if ( collid >= its->max_collections ) + return NULL; + + ret = vgic_access_guest_memory(its->d, addr + collid * sizeof(uint16_t), + &vcpu_id, sizeof(vcpu_id), false); + if ( ret ) + return NULL; + + if ( vcpu_id == UNMAPPED_COLLECTION || vcpu_id >= its->d->max_vcpus ) + return NULL; + + return its->d->vcpu[vcpu_id]; +} + +/* + * Our device table encodings: + * Contains the guest physical address of the Interrupt Translation Table in + * bits [51:8], and the size of it is encoded as the number of bits minus one + * in the lowest 8 bits of the word. + */ +#define DEV_TABLE_ITT_ADDR(x) ((x) & GENMASK_ULL(51, 8)) +#define DEV_TABLE_ITT_SIZE(x) (BIT(((x) & GENMASK_ULL(7, 0)) + 1)) +#define DEV_TABLE_ENTRY(addr, bits) \ + (((addr) & GENMASK_ULL(51, 8)) | (((bits) - 1) & GENMASK_ULL(7, 0))) + +/* + * Lookup the address of the Interrupt Translation Table associated with + * a device ID and return the address of the ITTE belonging to the event ID + * (which is an index into that table). + */ +static paddr_t its_get_itte_address(struct virt_its *its, + uint32_t devid, uint32_t evid) +{ + paddr_t addr = get_baser_phys_addr(its->baser_dev); + uint64_t itt; + + if ( devid >= its->max_devices ) + return INVALID_PADDR; + + if ( vgic_access_guest_memory(its->d, addr + devid * sizeof(uint64_t), + &itt, sizeof(itt), false) ) + return INVALID_PADDR; + + if ( evid >= DEV_TABLE_ITT_SIZE(itt) || + DEV_TABLE_ITT_ADDR(itt) == INVALID_PADDR ) + return INVALID_PADDR; + + return DEV_TABLE_ITT_ADDR(itt) + evid * sizeof(struct vits_itte); +} + +/* + * Queries the collection and device tables to get the vCPU and virtual + * LPI number for a given guest event. This first accesses the guest memory + * to resolve the address of the ITTE, then reads the ITTE entry at this + * address and puts the result in vcpu_ptr and vlpi_ptr. + * Requires the ITS lock to be held. + */ +static bool read_itte_locked(struct virt_its *its, uint32_t devid, + uint32_t evid, struct vcpu **vcpu_ptr, + uint32_t *vlpi_ptr) +{ + paddr_t addr; + struct vits_itte itte; + struct vcpu *vcpu; + + ASSERT(spin_is_locked(&its->its_lock)); + + addr = its_get_itte_address(its, devid, evid); + if ( addr == INVALID_PADDR ) + return false; + + if ( vgic_access_guest_memory(its->d, addr, &itte, sizeof(itte), false) ) + return false; + + vcpu = get_vcpu_from_collection(its, itte.collection); + if ( !vcpu ) + return false; + + *vcpu_ptr = vcpu; + *vlpi_ptr = itte.vlpi; + return true; +} + +/* + * This function takes care of the locking by taking the its_lock itself, so + * a caller shall not hold this. Before returning, the lock is dropped again. + */ +bool read_itte(struct virt_its *its, uint32_t devid, uint32_t evid, + struct vcpu **vcpu_ptr, uint32_t *vlpi_ptr) +{ + bool ret; + + spin_lock(&its->its_lock); + ret = read_itte_locked(its, devid, evid, vcpu_ptr, vlpi_ptr); + spin_unlock(&its->its_lock); + + return ret; +} + +/* + * Queries the collection and device tables to translate the device ID and + * event ID and find the appropriate ITTE. The given collection ID and the + * virtual LPI number are then stored into that entry. + * If vcpu_ptr is provided, returns the VCPU belonging to that collection. + * Requires the ITS lock to be held. + */ +static bool write_itte_locked(struct virt_its *its, uint32_t devid, + uint32_t evid, uint32_t collid, uint32_t vlpi, + struct vcpu **vcpu_ptr) +{ + paddr_t addr; + struct vits_itte itte; + + ASSERT(spin_is_locked(&its->its_lock)); + + if ( collid >= its->max_collections ) + return false; + + if ( vlpi >= its->d->arch.vgic.nr_lpis ) + return false; + + addr = its_get_itte_address(its, devid, evid); + if ( addr == INVALID_PADDR ) + return false; + + itte.collection = collid; + itte.vlpi = vlpi; + + if ( vgic_access_guest_memory(its->d, addr, &itte, sizeof(itte), true) ) + return false; + + if ( vcpu_ptr ) + *vcpu_ptr = get_vcpu_from_collection(its, collid); + + return true; +} + +/* + * This function takes care of the locking by taking the its_lock itself, so + * a caller shall not hold this. Before returning, the lock is dropped again. + */ +bool write_itte(struct virt_its *its, uint32_t devid, uint32_t evid, + uint32_t collid, uint32_t vlpi, struct vcpu **vcpu_ptr) +{ + bool ret; + + spin_lock(&its->its_lock); + ret = write_itte_locked(its, devid, evid, collid, vlpi, vcpu_ptr); + spin_unlock(&its->its_lock); + + return ret; +} + /************************************** * Functions that handle ITS commands * **************************************/