Received: by 10.192.165.156 with SMTP id m28csp522289imm; Fri, 13 Apr 2018 03:22:35 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+V7mYZKpHLNtPANC4u84PajT3bIZvA7Z4aZnIrW5jU83/tujGWycCFJ1P73k3yHj3Y1rUJ X-Received: by 10.99.177.9 with SMTP id r9mr3693155pgf.60.1523614955460; Fri, 13 Apr 2018 03:22:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523614955; cv=none; d=google.com; s=arc-20160816; b=xi/gP568XX39/tAYm9RetH7n4r9tcgJnIH97wmZGxg7KVL3BgvOX6rUnUh3MQB5xej N0+ko1RnVEnf/cdqHslTJ7vEWzL1Yo7Ul+vt1t9EuItGHLAwx4LD60Eycy2zhihR7qkP m1f4C3Zr5g+1QpQoyCcC0PqDFe9mie/GrHMz50TPUzrR/snPQm8xZO99onIP9ycnZMWv eVeWDMkNU2Hx0QRtjmGPFxjHD6Bu9pSuMEm6E+ZyXKrU13AWTQ99FmhOKC1uqXhPtUt/ lRDEIpI4uM62vC/TVRL2fxBaPCzD/SSflQwW/I/brxbvfk5OdFTPYNkFoAT/Nm7UyPdE 82Tg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=FuP4dPllL9cgNfw2+qJLweFajj/M+tZlnk7cQC/zdaY=; b=UVym9lVAtmdT+UqOTz3fXE6X9n3gqIB/hIu12R5dt3Bt9edRhkbAH4FfA4AfN6olYI kOErZ5vKO/NZcOWZoP5uxoYJAY7F7MZweWDukwT7w5MfgZeUKLcbAD3yqmHKh6BIVD2U 0CTlx8i0IdpLBi8xA+14e5nfu5GsDSc6e8Ifh0kl6aqyvUQkmIDgV6c+FJM+//uoK1X9 lg6Xr5bdehIjtg+/Pg7ynGQ6gKrByCIa/jWEhrg2BGmhJfqva9DP7iKiqQwKjqEBEhNu CR0+tEAMmf8R4G7GElM8k4Z7xHiO513BLkf2CGHclUwGnL/TGr70c+4h6E8sG4IVubha 5qkg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j188si3733763pgc.584.2018.04.13.03.22.21; Fri, 13 Apr 2018 03:22:35 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753612AbeDMIVV (ORCPT + 99 others); Fri, 13 Apr 2018 04:21:21 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:36128 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750973AbeDMIVS (ORCPT ); Fri, 13 Apr 2018 04:21:18 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 88C508160F99; Fri, 13 Apr 2018 08:21:17 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-192.ams2.redhat.com [10.36.116.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id 90220215CDC8; Fri, 13 Apr 2018 08:21:14 +0000 (UTC) From: Eric Auger To: eric.auger.pro@gmail.com, eric.auger@redhat.com, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, marc.zyngier@arm.com, cdall@kernel.org, peter.maydell@linaro.org Cc: andre.przywara@arm.com, drjones@redhat.com, wei@redhat.com Subject: [PATCH v3 06/12] KVM: arm/arm64: Helper to register a new redistributor region Date: Fri, 13 Apr 2018 10:20:52 +0200 Message-Id: <1523607658-9166-7-git-send-email-eric.auger@redhat.com> In-Reply-To: <1523607658-9166-1-git-send-email-eric.auger@redhat.com> References: <1523607658-9166-1-git-send-email-eric.auger@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 13 Apr 2018 08:21:17 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 13 Apr 2018 08:21:17 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'eric.auger@redhat.com' RCPT:'' Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org We introduce a new helper that creates and inserts a new redistributor region into the rdist region list. This helper both handles the case where the redistributor region size is known at registration time and the legacy case where it is not (eventually depending on the number of online vcpus). Depending on pfns, we perform all the possible checks that we can do: - end of memory crossing - incorrect alignment of the base address - collision with distributor region if already defined - collision with already registered rdist regions - check of the new index Rdist regions must be inserted by increasing order of indices. Indices must be contiguous. We also introduce vgic_v3_rdist_region_from_index() which will be used from the vgic kvm-device, later on. Signed-off-by: Eric Auger --- virt/kvm/arm/vgic/vgic-mmio-v3.c | 95 +++++++++++++++++++++++++++++++++------- virt/kvm/arm/vgic/vgic-v3.c | 29 ++++++++++++ virt/kvm/arm/vgic/vgic.h | 14 ++++++ 3 files changed, 122 insertions(+), 16 deletions(-) diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c index ce5c927..5273fb8 100644 --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c @@ -680,14 +680,66 @@ static int vgic_register_all_redist_iodevs(struct kvm *kvm) return ret; } -int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr) +/** + * vgic_v3_insert_redist_region - Insert a new redistributor region + * + * Performs various checks before inserting the rdist region in the list. + * Those tests depend on whether the size of the rdist region is known + * (ie. count != 0). The list is sorted by rdist region index. + * + * @kvm: kvm handle + * @index: redist region index + * @base: base of the new rdist region + * @count: number of redistributors the region is made of (of 0 in the old style + * single region, whose size is induced from the number of vcpus) + * + * Return 0 on success, < 0 otherwise + */ +static int vgic_v3_insert_redist_region(struct kvm *kvm, uint32_t index, + gpa_t base, uint32_t count) { - struct vgic_dist *vgic = &kvm->arch.vgic; + struct vgic_dist *d = &kvm->arch.vgic; struct vgic_redist_region *rdreg; + struct list_head *rd_regions = &d->rd_regions; + struct list_head *last = rd_regions->prev; + + gpa_t new_start, new_end; + size_t size = count * KVM_VGIC_V3_REDIST_SIZE; int ret; - /* vgic_check_ioaddr makes sure we don't do this twice */ - if (!list_empty(&vgic->rd_regions)) + /* single rdist region already set ?*/ + if (!count && !list_empty(rd_regions)) + return -EINVAL; + + /* cross the end of memory ? */ + if (base + size < base) + return -EINVAL; + + if (list_empty(rd_regions)) { + if (index != 0) + return -EINVAL; + } else { + rdreg = list_entry(last, struct vgic_redist_region, list); + if (index != rdreg->index + 1) + return -EINVAL; + + /* Cannot add an explicitly sized regions after legacy region */ + if (!rdreg->count) + return -EINVAL; + } + + /* + * collision with already set dist region ? + * this assumes we know the size of the new rdist region (pfns != 0) + * otherwise we can only test this when all vcpus are registered + */ + if (!count && !IS_VGIC_ADDR_UNDEF(d->vgic_dist_base) && + (!(d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE <= base)) && + (!(base + size <= d->vgic_dist_base))) + return -EINVAL; + + /* collision with any other rdist region? */ + if (vgic_v3_rdist_overlap(kvm, base, size)) return -EINVAL; rdreg = kzalloc(sizeof(*rdreg), GFP_KERNEL); @@ -696,17 +748,32 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr) rdreg->base = VGIC_ADDR_UNDEF; - ret = vgic_check_ioaddr(kvm, &rdreg->base, addr, SZ_64K); + ret = vgic_check_ioaddr(kvm, &rdreg->base, base, SZ_64K); if (ret) - goto out; + goto free; - rdreg->base = addr; - if (!vgic_v3_check_base(kvm)) { - ret = -EINVAL; - goto out; - } + rdreg->base = base; + rdreg->count = count; + rdreg->free_index = 0; + rdreg->index = index; - list_add(&rdreg->list, &vgic->rd_regions); + new_start = base; + new_end = base + size - 1; + + list_add_tail(&rdreg->list, rd_regions); + return 0; +free: + kfree(rdreg); + return ret; +} + +int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr) +{ + int ret; + + ret = vgic_v3_insert_redist_region(kvm, 0, addr, 0); + if (ret) + return ret; /* * Register iodevs for each existing VCPU. Adding more VCPUs @@ -717,10 +784,6 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr) return ret; return 0; - -out: - kfree(rdreg); - return ret; } int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr) diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c index 820012a..dbcba5f 100644 --- a/virt/kvm/arm/vgic/vgic-v3.c +++ b/virt/kvm/arm/vgic/vgic-v3.c @@ -410,6 +410,21 @@ int vgic_v3_save_pending_tables(struct kvm *kvm) return 0; } +/* return true if there is an overlap between any rdist */ +bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size) +{ + struct vgic_dist *d = &kvm->arch.vgic; + struct vgic_redist_region *rdreg; + + list_for_each_entry(rdreg, &d->rd_regions, list) { + if ((base + size <= rdreg->base) || + (rdreg->base + vgic_v3_rd_region_size(kvm, rdreg) <= base)) + continue; + return true; + } + return false; +} + /* * Check for overlapping regions and for regions crossing the end of memory * for base addresses which have already been set. @@ -461,6 +476,20 @@ struct vgic_redist_region *vgic_v3_rdist_free_slot(struct list_head *rd_regions) return NULL; } +struct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm, + uint32_t index) +{ + struct list_head *rd_regions = &kvm->arch.vgic.rd_regions; + struct vgic_redist_region *rdreg; + + list_for_each_entry(rdreg, rd_regions, list) { + if (rdreg->index == index) + return rdreg; + } + return NULL; +} + + int vgic_v3_map_resources(struct kvm *kvm) { int ret = 0; diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h index fea32cb..95b8345 100644 --- a/virt/kvm/arm/vgic/vgic.h +++ b/virt/kvm/arm/vgic/vgic.h @@ -262,6 +262,20 @@ vgic_v3_redist_region_full(struct vgic_redist_region *region) struct vgic_redist_region *vgic_v3_rdist_free_slot(struct list_head *rdregs); +static inline size_t +vgic_v3_rd_region_size(struct kvm *kvm, struct vgic_redist_region *rdreg) +{ + if (!rdreg->count) + return atomic_read(&kvm->online_vcpus) * KVM_VGIC_V3_REDIST_SIZE; + else + return rdreg->count * KVM_VGIC_V3_REDIST_SIZE; +} + +struct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm, + uint32_t index); + +bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size); + int vgic_its_resolve_lpi(struct kvm *kvm, struct vgic_its *its, u32 devid, u32 eventid, struct vgic_irq **irq); struct vgic_its *vgic_msi_to_its(struct kvm *kvm, struct kvm_msi *msi); -- 2.5.5