From patchwork Mon Apr 3 20:28:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 9660545 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 24ED06032D for ; Mon, 3 Apr 2017 20:28:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 15E8E28403 for ; Mon, 3 Apr 2017 20:28:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0A8CB2841C; Mon, 3 Apr 2017 20:28:54 +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 86B1F28403 for ; Mon, 3 Apr 2017 20:28:53 +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 1cv8Yt-00055G-ES; Mon, 03 Apr 2017 20:26:51 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cv8Yr-000535-Oc for xen-devel@lists.xenproject.org; Mon, 03 Apr 2017 20:26:49 +0000 Received: from [193.109.254.147] by server-4.bemta-6.messagelabs.com id 24/33-03012-900B2E85; Mon, 03 Apr 2017 20:26:49 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrGLMWRWlGSWpSXmKPExsVysyfVTZdjw6M IgwVrZC2+b5nM5MDocfjDFZYAxijWzLyk/IoE1owfBxYxFRw0qli34SRrA+M/tS5GLg4hgY2M EidOL2aGcJYzSqx+c4i9i5GTg01AV2LHzdfMILaIQKjE0wXfwWxmASWJ/WevMYLYwgJuEq82f wayOThYBFQlJrQbgYR5BawlLk27xwpiSwjISTScvw/WygkUb/14FKxVSMBKYsLDJqYJjNwLGB lWMWoUpxaVpRbpGhvpJRVlpmeU5CZm5ugaGpjp5aYWFyemp+YkJhXrJefnbmIE+pcBCHYwnl4 XeIhRkoNJSZRXfdKjCCG+pPyUyozE4oz4otKc1OJDjDIcHEoSvMfWAeUEi1LTUyvSMnOAgQaT luDgURLh3QyS5i0uSMwtzkyHSJ1iVJQS580ASQiAJDJK8+DaYMF9iVFWSpiXEegQIZ6C1KLcz BJU+VeM4hyMSsK8s0Gm8GTmlcBNfwW0mAlo8ZM7D0EWlyQipKQaGNc57naw1HvM5GGYoDuHM3 O/U+pd789CEc9Fw72PmlkWTzvEob4l1PFcn8WETU5hB9Vv73+33WzxhX9tKxa84pc0CDDwcxH wn7pcxmnz8sa92eUB3ideR9QpaLTE/K/k/rHosLtm4bS7jcLHv1jc3NOTONVl+yMRwZNfFi+K U0tWKlrBy9pppcRSnJFoqMVcVJwIALZ1zbhpAgAA X-Env-Sender: andre.przywara@arm.com X-Msg-Ref: server-14.tower-27.messagelabs.com!1491251207!82918495!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.2.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 21838 invoked from network); 3 Apr 2017 20:26:48 -0000 Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by server-14.tower-27.messagelabs.com with SMTP; 3 Apr 2017 20:26:48 -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 9ECDF2B; Mon, 3 Apr 2017 13:26:47 -0700 (PDT) Received: from e104803-lin.lan (unknown [10.1.207.46]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DCD553F4FF; Mon, 3 Apr 2017 13:26:46 -0700 (PDT) From: Andre Przywara To: Julien Grall , Stefano Stabellini Date: Mon, 3 Apr 2017 21:28:17 +0100 Message-Id: <20170403202829.7278-16-andre.przywara@arm.com> X-Mailer: git-send-email 2.9.0 In-Reply-To: <20170403202829.7278-1-andre.przywara@arm.com> References: <20170403202829.7278-1-andre.przywara@arm.com> Cc: xen-devel@lists.xenproject.org Subject: [Xen-devel] [PATCH v4 15/27] 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/vgic-v3-its.c | 183 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c index fd3b9a1..fcfea3b 100644 --- a/xen/arch/arm/vgic-v3-its.c +++ b/xen/arch/arm/vgic-v3-its.c @@ -71,6 +71,189 @@ static bool its_is_enabled(struct virt_its *its) return test_bit(VIRT_ITS_ENABLED, &its->flags); } +#define UNMAPPED_COLLECTION ((uint16_t)~0) + +/* + * 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 *coll_table; + uint16_t vcpu_id; + + if ( collid >= its->max_collections ) + return NULL; + + coll_table = map_one_guest_page(its->d, addr + collid * sizeof(uint16_t)); + if ( !coll_table ) + return NULL; + + vcpu_id = *coll_table; + + unmap_one_guest_page(coll_table); + + 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 encoded in the lowest 8 bits. + */ +#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 ret, addr = get_baser_phys_addr(its->baser_dev); + uint64_t *itt_ptr; + uint64_t itt; + + if ( devid >= its->max_devices ) + return INVALID_PADDR; + + itt_ptr = map_one_guest_page(its->d, addr + devid * sizeof(uint64_t)); + if ( !itt_ptr ) + return INVALID_PADDR; + + itt = read_u64_atomic(itt_ptr); + + if ( evid < DEV_TABLE_ITT_SIZE(itt) && + DEV_TABLE_ITT_ADDR(itt) != INVALID_PADDR ) + ret = DEV_TABLE_ITT_ADDR(itt) + evid * sizeof(struct vits_itte); + else + ret = INVALID_PADDR; + + unmap_one_guest_page(itt_ptr); + + return ret; +} + +/* + * 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_itte() to unmap + * the page again. + * Must be called with the ITS lock held. + */ +static struct vits_itte *get_itte(struct virt_its *its, + uint32_t devid, uint32_t evid) +{ + paddr_t addr = its_get_itte_address(its, devid, evid); + + if ( addr == INVALID_PADDR ) + return NULL; + + return map_one_guest_page(its->d, addr); +} + +/* Must be called with the ITS lock held. */ +static void put_itte(struct virt_its *its, struct vits_itte *itte) +{ + unmap_one_guest_page(itte); +} + +/* + * 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. + * This function takes care of the locking by taking the its_lock itself, so + * a caller shall not hold this. Upon returning, the lock is dropped again. + */ +bool read_itte(struct virt_its *its, uint32_t devid, uint32_t evid, + struct vcpu **vcpu, uint32_t *vlpi) +{ + struct vits_itte *itte; + uint16_t collid; + uint32_t _vlpi; + struct vcpu *_vcpu; + + spin_lock(&its->its_lock); + itte = get_itte(its, devid, evid); + if ( !itte ) + { + spin_unlock(&its->its_lock); + return false; + } + collid = itte->collection; + _vlpi = itte->vlpi; + put_itte(its, itte); + + _vcpu = get_vcpu_from_collection(its, collid); + spin_unlock(&its->its_lock); + + if ( !_vcpu ) + return false; + + *vcpu = _vcpu; + *vlpi = _vlpi; + + return true; +} + +#define SKIP_LPI_UPDATE 1 +/* + * This function takes care of the locking by taking the its_lock itself, so + * a caller shall not hold this. Upon 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) +{ + struct vits_itte *itte; + + if ( collid >= its->max_collections ) + return false; + + if ( vlpi >= its->d->arch.vgic.nr_lpis ) + return false; + + spin_lock(&its->its_lock); + itte = get_itte(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_itte(its, itte); + spin_unlock(&its->its_lock); + + return true; +} + /************************************** * Functions that handle ITS commands * **************************************/