From patchwork Mon Jan 30 18:31:41 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 9545887 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 1591060415 for ; Mon, 30 Jan 2017 18:33:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0D23527F82 for ; Mon, 30 Jan 2017 18:33:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 023B228173; Mon, 30 Jan 2017 18:33:12 +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 9593527F7F for ; Mon, 30 Jan 2017 18:33:12 +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 1cYGjD-00082G-El; Mon, 30 Jan 2017 18:30:59 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cYGjB-0007yc-Ra for xen-devel@lists.xenproject.org; Mon, 30 Jan 2017 18:30:57 +0000 Received: from [85.158.137.68] by server-7.bemta-3.messagelabs.com id 50/58-23854-1668F885; Mon, 30 Jan 2017 18:30:57 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrGLMWRWlGSWpSXmKPExsVysyfVTTehrT/ C4PUCeYvvWyYzOTB6HP5whSWAMYo1My8pvyKBNWPZnQOsBY2qFSs3L2NsYLwu08XIxSEksJlR 4ueXC2wQznJGiYXL+oEcTg42AV2JHTdfM4PYIgKhEnN+PgKyOTiYBbwkvrz3BgkLCzhLfJu9l gXEZhFQldi5eh9YK6+AjcSvFx/AbAkBOYmG8/fBxnACxWdv/s0EYgsJWEv861nOOIGRewEjwy pGjeLUorLUIl1jA72kosz0jJLcxMwcXUMDY73c1OLixPTUnMSkYr3k/NxNjED/1jMwMO5g7Dz hd4hRkoNJSZS372NfhBBfUn5KZUZicUZ8UWlOavEhRhkODiUJ3q7W/gghwaLU9NSKtMwcYKDB pCU4eJREeFNB0rzFBYm5xZnpEKlTjIpS4rx5IAkBkERGaR5cGyy4LzHKSgnzMjIwMAjxFKQW5 WaWoMq/YhTnYFQS5vUDmcKTmVcCN/0V0GImoMXur/pAFpckIqSkGhg5nPlKnmguz97jvvTbPZ 47f8MLbCan+y2e137T1cBxm3Ldfos4L9a4Tx8E5bIZBb60sz2wepfxxvAJ6+MP32XL+eyOa8z b/FSKwUnQkEl55bsbK/KEGXNqv5ZlT1+853klh3CJlcrdkn16XpM/p/2pLbq449bt3BlTLPZo Vp2ZqvkhcXHxp11KLMUZiYZazEXFiQDhkH15aQIAAA== X-Env-Sender: andre.przywara@arm.com X-Msg-Ref: server-10.tower-31.messagelabs.com!1485801055!82415337!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.1.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 6621 invoked from network); 30 Jan 2017 18:30:56 -0000 Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by server-10.tower-31.messagelabs.com with SMTP; 30 Jan 2017 18:30:56 -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 921591595; Mon, 30 Jan 2017 10:30:55 -0800 (PST) Received: from e104803-lin.lan (unknown [10.1.207.46]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B1BB13F24D; Mon, 30 Jan 2017 10:30:54 -0800 (PST) From: Andre Przywara To: Stefano Stabellini , Julien Grall Date: Mon, 30 Jan 2017 18:31:41 +0000 Message-Id: <20170130183153.28566-17-andre.przywara@arm.com> X-Mailer: git-send-email 2.9.0 In-Reply-To: <20170130183153.28566-1-andre.przywara@arm.com> References: <20170130183153.28566-1-andre.przywara@arm.com> Cc: xen-devel@lists.xenproject.org, Vijay Kilari Subject: [Xen-devel] [PATCH 16/28] 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. Since the final interrupt translation tables can be smaller than a page, we map them 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. Signed-off-by: Andre Przywara --- xen/arch/arm/vgic-v3-its.c | 135 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c index fc28376..982c51d 100644 --- a/xen/arch/arm/vgic-v3-its.c +++ b/xen/arch/arm/vgic-v3-its.c @@ -60,6 +60,141 @@ struct vits_itte uint16_t collection; }; +#define UNMAPPED_COLLECTION ((uint16_t)~0) + +/* Must be called with the ITS lock held. */ +static struct vcpu *get_vcpu_from_collection(struct virt_its *its, int collid) +{ + uint16_t vcpu_id; + + if ( collid >= its->max_collections ) + return NULL; + + vcpu_id = its->coll_table[collid]; + if ( vcpu_id == UNMAPPED_COLLECTION || vcpu_id >= its->d->max_vcpus ) + return NULL; + + return its->d->vcpu[vcpu_id]; +} + +#define DEV_TABLE_ITT_ADDR(x) ((x) & GENMASK(51, 8)) +#define DEV_TABLE_ITT_SIZE(x) (BIT(((x) & GENMASK(7, 0)) + 1)) +#define DEV_TABLE_ENTRY(addr, bits) \ + (((addr) & GENMASK(51, 8)) | (((bits) - 1) & GENMASK(7, 0))) + +static paddr_t get_itte_address(struct virt_its *its, + uint32_t devid, uint32_t evid) +{ + paddr_t addr; + + if ( devid >= its->max_devices ) + return ~0; + + if ( evid >= DEV_TABLE_ITT_SIZE(its->dev_table[devid]) ) + return ~0; + + addr = DEV_TABLE_ITT_ADDR(its->dev_table[devid]); + + return addr + evid * sizeof(struct vits_itte); +} + +/* + * Looks up a given deviceID/eventID pair on an ITS and returns a pointer to + * the corresponding ITTE. This maps the respective guest page into Xen. + * Once finished with handling the ITTE, call put_devid_evid() to unmap + * the page again. + * Must be called with the ITS lock held. + */ +static struct vits_itte *get_devid_evid(struct virt_its *its, + uint32_t devid, uint32_t evid) +{ + paddr_t addr = get_itte_address(its, devid, evid); + + if ( addr == ~0 ) + return NULL; + + return map_guest_pages(its->d, addr, 1); +} + +/* Must be called with the ITS lock held. */ +static void put_devid_evid(struct virt_its *its, struct vits_itte *itte) +{ + unmap_guest_pages(itte, 1); +} + +/* + * Queries the collection and device tables to get the vCPU and virtual + * LPI number for a given guest event. This takes care of mapping the + * respective tables and validating the values, since we can't efficiently + * protect the ITTs with their less-than-page-size granularity. + * Takes and drops the its_lock. + */ +bool read_itte(struct virt_its *its, uint32_t devid, uint32_t evid, + struct vcpu **vcpu, uint32_t *vlpi) +{ + struct vits_itte *itte; + int collid; + uint32_t _vlpi; + struct vcpu *_vcpu; + + spin_lock(&its->its_lock); + itte = get_devid_evid(its, devid, evid); + if ( !itte ) + { + spin_unlock(&its->its_lock); + return false; + } + collid = itte->collection; + _vlpi = itte->vlpi; + put_devid_evid(its, itte); + + _vcpu = get_vcpu_from_collection(its, collid); + spin_unlock(&its->its_lock); + + if ( !_vcpu ) + return false; + + if ( collid >= its->max_collections ) + return false; + + *vcpu = _vcpu; + *vlpi = _vlpi; + + return true; +} + +#define SKIP_LPI_UPDATE 1 +bool write_itte(struct virt_its *its, uint32_t devid, uint32_t evid, + uint32_t collid, uint32_t vlpi, struct vcpu **vcpu) +{ + struct vits_itte *itte; + + if ( collid >= its->max_collections ) + return false; + + /* TODO: validate vlpi */ + + spin_lock(&its->its_lock); + itte = get_devid_evid(its, devid, evid); + if ( !itte ) + { + spin_unlock(&its->its_lock); + return false; + } + + itte->collection = collid; + if ( vlpi != SKIP_LPI_UPDATE ) + itte->vlpi = vlpi; + + if ( vcpu ) + *vcpu = get_vcpu_from_collection(its, collid); + + put_devid_evid(its, itte); + spin_unlock(&its->its_lock); + + return true; +} + /************************************** * Functions that handle ITS commands * **************************************/