From patchwork Fri Sep 13 09:47:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11144295 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8D6C71599 for ; Fri, 13 Sep 2019 09:49:25 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5E48E20717 for ; Fri, 13 Sep 2019 09:49:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=citrix.com header.i=@citrix.com header.b="CvGDcH6q" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5E48E20717 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=citrix.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBF-0002Dw-7E; Fri, 13 Sep 2019 09:47:53 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBD-0002Dr-Iy for xen-devel@lists.xenproject.org; Fri, 13 Sep 2019 09:47:51 +0000 X-Inumbo-ID: 89ef66e4-d60b-11e9-a337-bc764e2007e4 Received: from esa3.hc3370-68.iphmx.com (unknown [216.71.145.155]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 89ef66e4-d60b-11e9-a337-bc764e2007e4; Fri, 13 Sep 2019 09:47:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1568368067; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zbpbfu78iUcEVPs3EtXOWgaUpnVSAvqFbJ2/Pq+RKik=; b=CvGDcH6qT3cUtDChyYMJWtQYz0ucYsCvFraTHOErteu8h7a0f3evS2qV nfdKNa5T94qVEmrdgBA1SSnvr6e3Ey8DwRart3KCrgNYK0NXiQKvtv2Pb ifbNn4iiehCfhBynpLM9NMMYguBWX1yiA3H9xbHFuPjZXg1LfH1vJK2Jj s=; Authentication-Results: esa3.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=paul.durrant@citrix.com; spf=Pass smtp.mailfrom=Paul.Durrant@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of paul.durrant@citrix.com) identity=pra; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="paul.durrant@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa3.hc3370-68.iphmx.com: domain of Paul.Durrant@citrix.com designates 162.221.158.21 as permitted sender) identity=mailfrom; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="Paul.Durrant@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:162.221.158.21 ip4:162.221.156.83 ~all" Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: mmtoLxkMZi3z/5KHgcnIxcCrKkmy9SDS4RU7ZdqDdoy7dUH+VT9tED8SeIFOpgYE4UDE8WX7m8 dkmHbDK10rz/X9xeSop/7smzGp+FELkgSaAOixLAYF88elrLYIim5UFiJYArVrlO+Ahaor3DXt 6eJKHUzDuJBNFEf9LAuCIwMwQpP52Pb6MGKuc/We5wnyenh4sn31/zpsaVsQaM506+miXQgYfI uUTgEGEYbsCNkCaREQpNdTB8pV6GyGDVhnoIbmDksufzGWoFftgcd7X4s++EpJfT4MHrBch1rH p1c= X-SBRS: 2.7 X-MesageID: 5528289 X-Ironport-Server: esa3.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.64,500,1559534400"; d="scan'208";a="5528289" From: Paul Durrant To: Date: Fri, 13 Sep 2019 10:47:36 +0100 Message-ID: <20190913094741.31451-2-paul.durrant@citrix.com> X-Mailer: git-send-email 2.20.1.2.gb21ebb671 In-Reply-To: <20190913094741.31451-1-paul.durrant@citrix.com> References: <20190913094741.31451-1-paul.durrant@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH v10 1/6] domain: introduce XEN_DOMCTL_CDF_iommu flag X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ian Jackson , Tim Deegan , Julien Grall , Paul Durrant , Christian Lindig , Jan Beulich , David Scott , Volodymyr Babchuk , =?utf-8?q?Roger_Pau_Monn?= =?utf-8?q?=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" This patch introduces a common domain creation flag to determine whether the domain is permitted to make use of the IOMMU. Currently the flag is always set for both dom0 and any domU created by libxl if the IOMMU is globally enabled (i.e. iommu_enabled == 1). sanitise_domain_config() is modified to reject the flag if !iommu_enabled. A new helper function, is_iommu_enabled(), is added to test the flag and iommu_domain_init() will return immediately if !is_iommu_enabled(). This is slightly different to the previous behaviour based on !iommu_enabled where the call to arch_iommu_domain_init() was made regardless, however it appears that this call was only necessary to initialize the dt_devices list for ARM such that iommu_release_dt_devices() can be called unconditionally by domain_relinquish_resources(). Adding a simple check of is_iommu_enabled() into iommu_release_dt_devices() keeps this unconditional call working. No functional change should be observed with this patch applied. Subsequent patches will allow the toolstack to control whether use of the IOMMU is enabled for a domain. NOTE: The introduction of the is_iommu_enabled() helper function might seem excessive but its use is expected to increase with subsequent patches. Also, having iommu_domain_init() bail before calling arch_iommu_domain_init() is not strictly necessary, but I think the consequent addition of the call to is_iommu_enabled() in iommu_release_dt_devices() makes the code clearer. Signed-off-by: Paul Durrant Reviewed-by: "Roger Pau Monné" Acked-by: Jan Beulich Acked-by: Christian Lindig --- Cc: David Scott Cc: Ian Jackson Cc: Wei Liu Cc: Andrew Cooper Cc: George Dunlap Cc: Julien Grall Cc: Konrad Rzeszutek Wilk Cc: Stefano Stabellini Cc: Tim Deegan Cc: Volodymyr Babchuk Previously part of series https://lists.xenproject.org/archives/html/xen-devel/2019-07/msg02267.html v9: - Fix oversight in ARM's arch_sanitise_domain_config() to tolerate setting of XEN_DOMCTL_CDF_iommu v7: - Add a check to verify that the toolstack has not set XEN_DOMCTL_CDF_iommu - Add missing ocaml binding changes v6: - Remove the toolstack parts as there's no nice method of testing whether the IOMMU is enabled in an architecture-neutral way v5: - Move is_iommu_enabled() check into iommu_domain_init() - Reject XEN_DOMCTL_CDF_iommu in sanitise_domain_config() if !iommu_enabled - Use evaluate_nospec() in defintion of is_iommu_enabled() --- tools/ocaml/libs/xc/xenctrl.ml | 1 + tools/ocaml/libs/xc/xenctrl.mli | 1 + xen/arch/arm/domain.c | 7 +++++-- xen/arch/arm/setup.c | 3 +++ xen/arch/x86/setup.c | 3 +++ xen/common/domain.c | 9 ++++++++- xen/common/domctl.c | 13 +++++++++++++ xen/drivers/passthrough/device_tree.c | 3 +++ xen/drivers/passthrough/iommu.c | 6 +++--- xen/include/public/domctl.h | 5 ++++- xen/include/xen/sched.h | 5 +++++ 11 files changed, 49 insertions(+), 7 deletions(-) diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml index 43aafa7e22..35dddbbd9c 100644 --- a/tools/ocaml/libs/xc/xenctrl.ml +++ b/tools/ocaml/libs/xc/xenctrl.ml @@ -63,6 +63,7 @@ type domain_create_flag = | CDF_S3_INTEGRITY | CDF_OOS_OFF | CDF_XS_DOMAIN + | CDF_IOMMU type domctl_create_config = { diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli index 1bcfa3f839..0dd55e9d8b 100644 --- a/tools/ocaml/libs/xc/xenctrl.mli +++ b/tools/ocaml/libs/xc/xenctrl.mli @@ -56,6 +56,7 @@ type domain_create_flag = | CDF_S3_INTEGRITY | CDF_OOS_OFF | CDF_XS_DOMAIN + | CDF_IOMMU type domctl_create_config = { ssidref: int32; diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index a9c4113c26..ae13e47e86 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -608,9 +608,12 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config) { unsigned int max_vcpus; - if ( config->flags != (XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap) ) + /* HVM and HAP must be set. IOMMU may or may not be */ + if ( (config->flags & ~XEN_DOMCTL_CDF_iommu) != + (XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap) ) { - dprintk(XENLOG_INFO, "Unsupported configuration %#x\n", config->flags); + dprintk(XENLOG_INFO, "Unsupported configuration %#x\n", + config->flags); return -EINVAL; } diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 1b303bde34..ad101784e6 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -961,6 +961,9 @@ void __init start_xen(unsigned long boot_phys_offset, dom0_cfg.arch.tee_type = tee_get_type(); dom0_cfg.max_vcpus = dom0_max_vcpus(); + if ( iommu_enabled ) + dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu; + dom0 = domain_create(0, &dom0_cfg, true); if ( IS_ERR(dom0) || (alloc_dom0_vcpu0(dom0) == NULL) ) panic("Error creating domain 0\n"); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 27981adc0b..dec60d0301 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -1732,6 +1732,9 @@ void __init noreturn __start_xen(unsigned long mbi_p) } dom0_cfg.max_vcpus = dom0_max_vcpus(); + if ( iommu_enabled ) + dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu; + /* Create initial domain 0. */ dom0 = domain_create(get_initial_domain_id(), &dom0_cfg, !pv_shim); if ( IS_ERR(dom0) || (alloc_dom0_vcpu0(dom0) == NULL) ) diff --git a/xen/common/domain.c b/xen/common/domain.c index 09917b2885..4681f29c8b 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -301,7 +301,8 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config) XEN_DOMCTL_CDF_hap | XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off | - XEN_DOMCTL_CDF_xs_domain) ) + XEN_DOMCTL_CDF_xs_domain | + XEN_DOMCTL_CDF_iommu) ) { dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags); return -EINVAL; @@ -320,6 +321,12 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config) return -EINVAL; } + if ( (config->flags & XEN_DOMCTL_CDF_iommu) && !iommu_enabled ) + { + dprintk(XENLOG_INFO, "IOMMU is not enabled\n"); + return -EINVAL; + } + return arch_sanitise_domain_config(config); } diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 6e6e9b9866..5dcfe3c8f6 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -515,6 +515,19 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) rover = dom; } + /* + * For now, make sure the createdomain IOMMU flag is set if the + * IOMMU is enabled. When the flag comes under toolstack control + * this can go away. + */ + if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_iommu ) + { + ASSERT_UNREACHABLE(); + return -EINVAL; + } + if ( iommu_enabled ) + op->u.createdomain.flags |= XEN_DOMCTL_CDF_iommu; + d = domain_create(dom, &op->u.createdomain, false); if ( IS_ERR(d) ) { diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c index b6eaae7283..d32b172664 100644 --- a/xen/drivers/passthrough/device_tree.c +++ b/xen/drivers/passthrough/device_tree.c @@ -119,6 +119,9 @@ int iommu_release_dt_devices(struct domain *d) struct dt_device_node *dev, *_dev; int rc; + if ( !is_iommu_enabled(d) ) + return 0; + list_for_each_entry_safe(dev, _dev, &hd->dt_devices, domain_list) { rc = iommu_deassign_dt_device(d, dev); diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index b82f778479..f42402bc92 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -151,6 +151,9 @@ int iommu_domain_init(struct domain *d) struct domain_iommu *hd = dom_iommu(d); int ret = 0; + if ( !is_iommu_enabled(d) ) + return 0; + #ifdef CONFIG_NUMA hd->node = NUMA_NO_NODE; #endif @@ -159,9 +162,6 @@ int iommu_domain_init(struct domain *d) if ( ret ) return ret; - if ( !iommu_enabled ) - return 0; - hd->platform_ops = iommu_get_ops(); return hd->platform_ops->init(d); } diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 77f546cbb8..1b3176adb5 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -64,9 +64,12 @@ struct xen_domctl_createdomain { /* Is this a xenstore domain? */ #define _XEN_DOMCTL_CDF_xs_domain 4 #define XEN_DOMCTL_CDF_xs_domain (1U<<_XEN_DOMCTL_CDF_xs_domain) + /* Should this domain be permitted to use the IOMMU? */ +#define _XEN_DOMCTL_CDF_iommu 5 +#define XEN_DOMCTL_CDF_iommu (1U<<_XEN_DOMCTL_CDF_iommu) /* Max XEN_DOMCTL_CDF_* constant. Used for ABI checking. */ -#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_xs_domain +#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_iommu uint32_t flags; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index e3601c1935..2d17c84915 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -983,6 +983,11 @@ static inline bool is_xenstore_domain(const struct domain *d) return d->options & XEN_DOMCTL_CDF_xs_domain; } +static inline bool is_iommu_enabled(const struct domain *d) +{ + return evaluate_nospec(d->options & XEN_DOMCTL_CDF_iommu); +} + extern bool sched_smt_power_savings; extern enum cpufreq_controller { From patchwork Fri Sep 13 09:47:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11144297 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 469BF1599 for ; Fri, 13 Sep 2019 09:49:42 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1769020717 for ; Fri, 13 Sep 2019 09:49:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=citrix.com header.i=@citrix.com header.b="etdkbWv5" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1769020717 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=citrix.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBT-0002LL-RO; Fri, 13 Sep 2019 09:48:07 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBS-0002KM-IF for xen-devel@lists.xenproject.org; Fri, 13 Sep 2019 09:48:06 +0000 X-Inumbo-ID: 8ba57b5e-d60b-11e9-a337-bc764e2007e4 Received: from esa3.hc3370-68.iphmx.com (unknown [216.71.145.155]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 8ba57b5e-d60b-11e9-a337-bc764e2007e4; Fri, 13 Sep 2019 09:47:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1568368069; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=3DNy0euenOg8CEGK6mzqIiUDvcThifdwmjtKi5kp96s=; b=etdkbWv5RIkKd5ghmgg0shpX5nPy9FfzSzbze1O4elEhvF+naJRKjJXJ ZBLXmvcOe85HtVHiYC1bKvlk1TmcbWTh49xcqJcynrOrsgYcx7sKm51Fk xOcJmLdRq84OqQnoxyolwAUOmpYf1okDrbrJOMTbUcA76769U5zcKopnC 4=; Authentication-Results: esa3.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=paul.durrant@citrix.com; spf=Pass smtp.mailfrom=Paul.Durrant@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of paul.durrant@citrix.com) identity=pra; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="paul.durrant@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa3.hc3370-68.iphmx.com: domain of Paul.Durrant@citrix.com designates 162.221.158.21 as permitted sender) identity=mailfrom; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="Paul.Durrant@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:162.221.158.21 ip4:162.221.156.83 ~all" Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: iSZEIkoZFw5XnZlNrOlwDRcLdZxTUbnAF51+rYxq80ncKneUX81QpLYuteODpkhs4GVEnVD6U4 S1eswf9jyQiWicnuUAMhcC7YlI3NRgZetxk9d1k1lTddcyfVbapidmiqQuhLVSKqpFp9OGL72N 0zVGpTAiE4kvkiUoWijpgymxtza0RFUuwS5FjxH9itUfNPGyBW4ccDHhqzrdRtLbOdU3EFJ4ea Tdzp9xuhy2joBavZB7Vjhf4Jt3NBa9QylcniGoSoP2sDtzTPdtRRuj7+1lI3jytosfs9ZoCNqt 60g= X-SBRS: 2.7 X-MesageID: 5528292 X-Ironport-Server: esa3.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.64,500,1559534400"; d="scan'208";a="5528292" From: Paul Durrant To: Date: Fri, 13 Sep 2019 10:47:37 +0100 Message-ID: <20190913094741.31451-3-paul.durrant@citrix.com> X-Mailer: git-send-email 2.20.1.2.gb21ebb671 In-Reply-To: <20190913094741.31451-1-paul.durrant@citrix.com> References: <20190913094741.31451-1-paul.durrant@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH v10 2/6] use is_iommu_enabled() where appropriate... X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Kevin Tian , Stefano Stabellini , Jun Nakajima , Wei Liu , George Dunlap , Andrew Cooper , Julien Grall , Paul Durrant , Jan Beulich , Daniel De Graaf , Volodymyr Babchuk , Suravee Suthikulpanit , =?utf-8?q?Roger_Pau_?= =?utf-8?q?Monn=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" ...rather than testing the global iommu_enabled flag and ops pointer. Now that there is a per-domain flag indicating whether the domain is permitted to use the IOMMU (which determines whether the ops pointer will be set), many tests of the global iommu_enabled flag and ops pointer can be translated into tests of the per-domain flag. Some of the other tests of purely the global iommu_enabled flag can also be translated into tests of the per-domain flag. NOTE: The comment in iommu_share_p2m_table() is also fixed; need_iommu() disappeared some time ago. Also, whilst the style of the 'if' in flask_iommu_resource_use_perm() is fixed, I have not translated any instances of u32 into uint32_t to keep consistency. IMO such a translation would be better done globally for the source module in a separate patch. The change to the definition of iommu_call() is to keep the PV shim build happy. Without this change it will fail to compile with errors of the form: iommu.c:361:32: error: unused variable ‘hd’ [-Werror=unused-variable] const struct domain_iommu *hd = dom_iommu(d); ^~ Signed-off-by: Paul Durrant Reviewed-by: "Roger Pau Monné" Reviewed-by: Kevin Tian Acked-by: Daniel De Graaf Reviewed-by: Jan Beulich Acked-by: Julien Grall --- Cc: Stefano Stabellini Cc: Volodymyr Babchuk Cc: Andrew Cooper Cc: Wei Liu Cc: Jun Nakajima Cc: George Dunlap Cc: Suravee Suthikulpanit Previously part of series https://lists.xenproject.org/archives/html/xen-devel/2019-07/msg02267.html v7: - Fix iommu_call() rather than messing with the initializtion of 'hd' - Constify domain pointer passed to flask_iommu_resource_use_perm() v5: - Fix logic in ARM p2m_init() - Make iommu_do_domctl() return -EOPNOTSUPP rather than -ENOSYS if the IOMMU is not enabled - Fix test in pci_enable_acs() - Fix test in flask_iommu_resource_use_perm() --- xen/arch/arm/p2m.c | 2 +- xen/arch/x86/dom0_build.c | 2 +- xen/arch/x86/domctl.c | 4 +-- xen/arch/x86/hvm/hvm.c | 6 ++--- xen/arch/x86/hvm/vioapic.c | 2 +- xen/arch/x86/hvm/vmx/vmcs.c | 2 +- xen/arch/x86/hvm/vmx/vmx.c | 2 +- xen/arch/x86/mm/p2m-ept.c | 4 +-- xen/drivers/passthrough/amd/iommu_guest.c | 2 +- xen/drivers/passthrough/device_tree.c | 4 +-- xen/drivers/passthrough/io.c | 8 +++--- xen/drivers/passthrough/iommu.c | 31 ++++++++++------------- xen/drivers/passthrough/pci.c | 16 ++++++------ xen/drivers/passthrough/vtd/iommu.c | 2 +- xen/drivers/passthrough/vtd/x86/hvm.c | 2 +- xen/drivers/passthrough/x86/iommu.c | 2 +- xen/include/asm-x86/iommu.h | 11 ++++++-- xen/xsm/flask/hooks.c | 18 ++++++------- 18 files changed, 62 insertions(+), 58 deletions(-) diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index e28ea1c85a..7f1442932a 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -1531,7 +1531,7 @@ int p2m_init(struct domain *d) * shared with the CPU, Xen has to make sure that the PT changes have * reached the memory */ - p2m->clean_pte = iommu_enabled && + p2m->clean_pte = is_iommu_enabled(d) && !iommu_has_feature(d, IOMMU_FEAT_COHERENT_WALK); rc = p2m_alloc_table(d); diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index c69570920c..d381784edd 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -356,7 +356,7 @@ unsigned long __init dom0_compute_nr_pages( avail -= d->max_vcpus - 1; /* Reserve memory for iommu_dom0_init() (rough estimate). */ - if ( iommu_enabled ) + if ( is_iommu_enabled(d) ) { unsigned int s; diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index a744696c6b..d1334c7112 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -708,7 +708,7 @@ long arch_do_domctl( break; ret = -ESRCH; - if ( iommu_enabled ) + if ( is_iommu_enabled(d) ) { pcidevs_lock(); ret = pt_irq_create_bind(d, bind); @@ -737,7 +737,7 @@ long arch_do_domctl( if ( ret ) break; - if ( iommu_enabled ) + if ( is_iommu_enabled(d) ) { pcidevs_lock(); ret = pt_irq_destroy_bind(d, bind); diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 452ac4833d..3831c6d4c1 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -465,7 +465,7 @@ void hvm_migrate_timers(struct vcpu *v) void hvm_migrate_pirq(struct hvm_pirq_dpci *pirq_dpci, const struct vcpu *v) { - ASSERT(iommu_enabled && + ASSERT(is_iommu_enabled(v->domain) && (is_hardware_domain(v->domain) || hvm_domain_irq(v->domain)->dpci)); if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MACH_MSI) && @@ -496,7 +496,7 @@ void hvm_migrate_pirqs(struct vcpu *v) { struct domain *d = v->domain; - if ( !iommu_enabled || !hvm_domain_irq(d)->dpci ) + if ( !is_iommu_enabled(d) || !hvm_domain_irq(d)->dpci ) return; spin_lock(&d->event_lock); @@ -2264,7 +2264,7 @@ int hvm_set_cr0(unsigned long value, bool may_defer) } if ( ((value ^ old_value) & X86_CR0_CD) && - iommu_enabled && hvm_funcs.handle_cd && + is_iommu_enabled(d) && hvm_funcs.handle_cd && (!rangeset_is_empty(d->iomem_caps) || !rangeset_is_empty(d->arch.ioport_caps) || has_arch_pdevs(d)) ) diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c index 9c25f72b4d..9aeef32a14 100644 --- a/xen/arch/x86/hvm/vioapic.c +++ b/xen/arch/x86/hvm/vioapic.c @@ -536,7 +536,7 @@ void vioapic_update_EOI(struct domain *d, u8 vector) ent->fields.remote_irr = 0; - if ( iommu_enabled ) + if ( is_iommu_enabled(d) ) { spin_unlock(&d->arch.hvm.irq_lock); hvm_dpci_eoi(d, vioapic->base_gsi + pin, ent); diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 16f14abe8f..ed27e8def7 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -1087,7 +1087,7 @@ static int construct_vmcs(struct vcpu *v) vmx_clear_msr_intercept(v, MSR_IA32_SYSENTER_CS, VMX_MSR_RW); vmx_clear_msr_intercept(v, MSR_IA32_SYSENTER_ESP, VMX_MSR_RW); vmx_clear_msr_intercept(v, MSR_IA32_SYSENTER_EIP, VMX_MSR_RW); - if ( paging_mode_hap(d) && (!iommu_enabled || iommu_snoop) ) + if ( paging_mode_hap(d) && (!is_iommu_enabled(d) || iommu_snoop) ) vmx_clear_msr_intercept(v, MSR_IA32_CR_PAT, VMX_MSR_RW); if ( (vmexit_ctl & VM_EXIT_CLEAR_BNDCFGS) && (vmentry_ctl & VM_ENTRY_LOAD_BNDCFGS) ) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 0060310d74..3b3d5b6250 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1210,7 +1210,7 @@ static void vmx_handle_cd(struct vcpu *v, unsigned long value) { v->arch.hvm.cache_mode = NORMAL_CACHE_MODE; vmx_set_guest_pat(v, *pat); - if ( !iommu_enabled || iommu_snoop ) + if ( !is_iommu_enabled(v->domain) || iommu_snoop ) vmx_clear_msr_intercept(v, MSR_IA32_CR_PAT, VMX_MSR_RW); hvm_asid_flush_vcpu(v); /* no need to flush cache */ } diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index d0e62905f8..220990f017 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -260,7 +260,7 @@ static bool_t ept_split_super_page(struct p2m_domain *p2m, *epte = *ept_entry; epte->sp = (level > 1); epte->mfn += i * trunk; - epte->snp = (iommu_enabled && iommu_snoop); + epte->snp = is_iommu_enabled(p2m->domain) && iommu_snoop; epte->suppress_ve = 1; ept_p2m_type_to_flags(p2m, epte, epte->sa_p2mt, epte->access); @@ -772,7 +772,7 @@ ept_set_entry(struct p2m_domain *p2m, gfn_t gfn_, mfn_t mfn, new_entry.sp = !!i; new_entry.sa_p2mt = p2mt; new_entry.access = p2ma; - new_entry.snp = (iommu_enabled && iommu_snoop); + new_entry.snp = is_iommu_enabled(d) && iommu_snoop; /* the caller should take care of the previous page */ new_entry.mfn = mfn_x(mfn); diff --git a/xen/drivers/passthrough/amd/iommu_guest.c b/xen/drivers/passthrough/amd/iommu_guest.c index 7f2dd662af..1f2bcfbe15 100644 --- a/xen/drivers/passthrough/amd/iommu_guest.c +++ b/xen/drivers/passthrough/amd/iommu_guest.c @@ -821,7 +821,7 @@ int guest_iommu_init(struct domain* d) struct guest_iommu *iommu; struct domain_iommu *hd = dom_iommu(d); - if ( !is_hvm_domain(d) || !iommu_enabled || !iommuv2_enabled || + if ( !is_hvm_domain(d) || !is_iommu_enabled(d) || !iommuv2_enabled || !has_viommu(d) ) return 0; diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c index d32b172664..12f2c4c3f2 100644 --- a/xen/drivers/passthrough/device_tree.c +++ b/xen/drivers/passthrough/device_tree.c @@ -29,7 +29,7 @@ int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev) int rc = -EBUSY; struct domain_iommu *hd = dom_iommu(d); - if ( !iommu_enabled || !hd->platform_ops ) + if ( !is_iommu_enabled(d) ) return -EINVAL; if ( !dt_device_is_protected(dev) ) @@ -71,7 +71,7 @@ int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev) const struct domain_iommu *hd = dom_iommu(d); int rc; - if ( !iommu_enabled || !hd->platform_ops ) + if ( !is_iommu_enabled(d) ) return -EINVAL; if ( !dt_device_is_protected(dev) ) diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index 4290c7c710..b292e79382 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -434,7 +434,7 @@ int pt_irq_create_bind( if ( vcpu ) pirq_dpci->gmsi.posted = true; } - if ( vcpu && iommu_enabled ) + if ( vcpu && is_iommu_enabled(d) ) hvm_migrate_pirq(pirq_dpci, vcpu); /* Use interrupt posting if it is supported. */ @@ -817,7 +817,7 @@ int hvm_do_IRQ_dpci(struct domain *d, struct pirq *pirq) ASSERT(is_hvm_domain(d)); - if ( !iommu_enabled || (!is_hardware_domain(d) && !dpci) || + if ( !is_iommu_enabled(d) || (!is_hardware_domain(d) && !dpci) || !pirq_dpci || !(pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) ) return 0; @@ -869,7 +869,7 @@ static int _hvm_dpci_msi_eoi(struct domain *d, void hvm_dpci_msi_eoi(struct domain *d, int vector) { - if ( !iommu_enabled || + if ( !is_iommu_enabled(d) || (!hvm_domain_irq(d)->dpci && !is_hardware_domain(d)) ) return; @@ -1001,7 +1001,7 @@ void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi, const struct hvm_irq_dpci *hvm_irq_dpci; const struct hvm_girq_dpci_mapping *girq; - if ( !iommu_enabled ) + if ( !is_iommu_enabled(d) ) return; if ( is_hardware_domain(d) ) diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index f42402bc92..09ce9d9294 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -183,7 +183,7 @@ void __hwdom_init iommu_hwdom_init(struct domain *d) check_hwdom_reqs(d); - if ( !iommu_enabled ) + if ( !is_iommu_enabled(d) ) return; register_keyhandler('o', &iommu_dump_p2m_table, "dump iommu p2m table", 0); @@ -288,7 +288,7 @@ int iommu_construct(struct domain *d) void iommu_domain_destroy(struct domain *d) { - if ( !iommu_enabled || !dom_iommu(d)->platform_ops ) + if ( !is_iommu_enabled(d) ) return; iommu_teardown(d); @@ -304,7 +304,7 @@ int iommu_map(struct domain *d, dfn_t dfn, mfn_t mfn, unsigned long i; int rc = 0; - if ( !iommu_enabled || !hd->platform_ops ) + if ( !is_iommu_enabled(d) ) return 0; ASSERT(IS_ALIGNED(dfn_x(dfn), (1ul << page_order))); @@ -364,7 +364,7 @@ int iommu_unmap(struct domain *d, dfn_t dfn, unsigned int page_order, unsigned long i; int rc = 0; - if ( !iommu_enabled || !hd->platform_ops ) + if ( !is_iommu_enabled(d) ) return 0; ASSERT(IS_ALIGNED(dfn_x(dfn), (1ul << page_order))); @@ -417,7 +417,7 @@ int iommu_lookup_page(struct domain *d, dfn_t dfn, mfn_t *mfn, { const struct domain_iommu *hd = dom_iommu(d); - if ( !iommu_enabled || !hd->platform_ops || !hd->platform_ops->lookup_page ) + if ( !is_iommu_enabled(d) || !hd->platform_ops->lookup_page ) return -EOPNOTSUPP; return iommu_call(hd->platform_ops, lookup_page, d, dfn, mfn, flags); @@ -446,8 +446,8 @@ int iommu_iotlb_flush(struct domain *d, dfn_t dfn, unsigned int page_count, const struct domain_iommu *hd = dom_iommu(d); int rc; - if ( !iommu_enabled || !hd->platform_ops || - !hd->platform_ops->iotlb_flush || !page_count || !flush_flags ) + if ( !is_iommu_enabled(d) || !hd->platform_ops->iotlb_flush || + !page_count || !flush_flags ) return 0; if ( dfn_eq(dfn, INVALID_DFN) ) @@ -474,8 +474,8 @@ int iommu_iotlb_flush_all(struct domain *d, unsigned int flush_flags) const struct domain_iommu *hd = dom_iommu(d); int rc; - if ( !iommu_enabled || !hd->platform_ops || - !hd->platform_ops->iotlb_flush_all || !flush_flags ) + if ( !is_iommu_enabled(d) || !hd->platform_ops->iotlb_flush_all || + !flush_flags ) return 0; /* @@ -560,8 +560,8 @@ int iommu_do_domctl( { int ret = -ENODEV; - if ( !iommu_enabled ) - return -ENOSYS; + if ( !is_iommu_enabled(d) ) + return -EOPNOTSUPP; #ifdef CONFIG_HAS_PCI ret = iommu_do_pci_domctl(domctl, d, u_domctl); @@ -580,9 +580,9 @@ void iommu_share_p2m_table(struct domain* d) ASSERT(hap_enabled(d)); /* * iommu_use_hap_pt(d) cannot be used here because during domain - * construction need_iommu(d) will always return false here. + * construction has_iommu_pt(d) will always return false here. */ - if ( iommu_enabled && iommu_hap_pt_share ) + if ( is_iommu_enabled(d) && iommu_hap_pt_share ) iommu_get_ops()->share_p2m(d); } @@ -612,10 +612,7 @@ int iommu_get_reserved_device_memory(iommu_grdm_t *func, void *ctxt) bool_t iommu_has_feature(struct domain *d, enum iommu_feature feature) { - if ( !iommu_enabled ) - return 0; - - return test_bit(feature, dom_iommu(d)->features); + return is_iommu_enabled(d) && test_bit(feature, dom_iommu(d)->features); } static void iommu_dump_p2m_table(unsigned char key) diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index af011d32dc..814106679f 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -595,7 +595,7 @@ static void pci_enable_acs(struct pci_dev *pdev) u16 cap, ctrl, seg = pdev->seg; u8 bus = pdev->bus; - if ( !iommu_enabled ) + if ( !is_iommu_enabled(pdev->domain) ) return; pos = pci_find_ext_capability(seg, bus, pdev->devfn, PCI_EXT_CAP_ID_ACS); @@ -864,7 +864,7 @@ static int pci_clean_dpci_irqs(struct domain *d) { struct hvm_irq_dpci *hvm_irq_dpci = NULL; - if ( !iommu_enabled ) + if ( !is_iommu_enabled(d) ) return 0; if ( !is_hvm_domain(d) ) @@ -897,7 +897,7 @@ static int deassign_device(struct domain *d, uint16_t seg, uint8_t bus, struct pci_dev *pdev; int ret = 0; - if ( !iommu_enabled || !hd->platform_ops ) + if ( !is_iommu_enabled(d) ) return -EINVAL; ASSERT(pcidevs_locked()); @@ -1383,7 +1383,7 @@ static int iommu_add_device(struct pci_dev *pdev) ASSERT(pcidevs_locked()); hd = dom_iommu(pdev->domain); - if ( !iommu_enabled || !hd->platform_ops ) + if ( !is_iommu_enabled(pdev->domain) ) return 0; rc = hd->platform_ops->add_device(pdev->devfn, pci_to_dev(pdev)); @@ -1412,7 +1412,7 @@ static int iommu_enable_device(struct pci_dev *pdev) ASSERT(pcidevs_locked()); hd = dom_iommu(pdev->domain); - if ( !iommu_enabled || !hd->platform_ops || + if ( !is_iommu_enabled(pdev->domain) || !hd->platform_ops->enable_device ) return 0; @@ -1428,7 +1428,7 @@ static int iommu_remove_device(struct pci_dev *pdev) return -EINVAL; hd = dom_iommu(pdev->domain); - if ( !iommu_enabled || !hd->platform_ops ) + if ( !is_iommu_enabled(pdev->domain) ) return 0; for ( devfn = pdev->devfn ; pdev->phantom_stride; ) @@ -1471,7 +1471,7 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) struct pci_dev *pdev; int rc = 0; - if ( !iommu_enabled || !hd->platform_ops ) + if ( !is_iommu_enabled(d) ) return 0; /* Prevent device assign if mem paging or mem sharing have been @@ -1537,7 +1537,7 @@ static int iommu_get_device_group( int i = 0; const struct iommu_ops *ops = hd->platform_ops; - if ( !iommu_enabled || !ops || !ops->get_device_group_id ) + if ( !is_iommu_enabled(d) || !ops->get_device_group_id ) return 0; group_id = ops->get_device_group_id(seg, bus, devfn); diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 04d46f7eab..7ffafdc065 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -1719,7 +1719,7 @@ static void iommu_domain_teardown(struct domain *d) xfree(mrmrr); } - ASSERT(iommu_enabled); + ASSERT(is_iommu_enabled(d)); /* * We can't use iommu_use_hap_pt here because either IOMMU state diff --git a/xen/drivers/passthrough/vtd/x86/hvm.c b/xen/drivers/passthrough/vtd/x86/hvm.c index 6675dca027..f77b35815c 100644 --- a/xen/drivers/passthrough/vtd/x86/hvm.c +++ b/xen/drivers/passthrough/vtd/x86/hvm.c @@ -51,7 +51,7 @@ void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq) struct hvm_irq_dpci *dpci = NULL; ASSERT(isairq < NR_ISAIRQS); - if ( !iommu_enabled ) + if ( !is_iommu_enabled(d) ) return; spin_lock(&d->event_lock); diff --git a/xen/drivers/passthrough/x86/iommu.c b/xen/drivers/passthrough/x86/iommu.c index 92c1d01edf..8319fe0a69 100644 --- a/xen/drivers/passthrough/x86/iommu.c +++ b/xen/drivers/passthrough/x86/iommu.c @@ -180,7 +180,7 @@ int arch_iommu_populate_page_table(struct domain *d) void __hwdom_init arch_iommu_check_autotranslated_hwdom(struct domain *d) { - if ( !iommu_enabled ) + if ( !is_iommu_enabled(d) ) panic("Presently, iommu must be enabled for PVH hardware domain\n"); } diff --git a/xen/include/asm-x86/iommu.h b/xen/include/asm-x86/iommu.h index facf835ada..31fda4b0cf 100644 --- a/xen/include/asm-x86/iommu.h +++ b/xen/include/asm-x86/iommu.h @@ -61,8 +61,15 @@ extern struct iommu_ops iommu_ops; #ifdef NDEBUG # include -# define iommu_call(ops, fn, args...) alternative_call(iommu_ops.fn, ## args) -# define iommu_vcall(ops, fn, args...) alternative_vcall(iommu_ops.fn, ## args) +# define iommu_call(ops, fn, args...) ({ \ + (void)(ops); \ + alternative_call(iommu_ops.fn, ## args); \ +}) + +# define iommu_vcall(ops, fn, args...) ({ \ + (void)(ops); \ + alternative_vcall(iommu_ops.fn, ## args); \ +}) #endif static inline const struct iommu_ops *iommu_get_ops(void) diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 6800f2d9a0..a449869550 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -883,7 +883,7 @@ static int flask_map_domain_msi (struct domain *d, int irq, const void *data, #endif } -static u32 flask_iommu_resource_use_perm(void) +static u32 flask_iommu_resource_use_perm(const struct domain *d) { /* Obtain the permission level required for allowing a domain * to use an assigned device. @@ -896,7 +896,7 @@ static u32 flask_iommu_resource_use_perm(void) */ u32 perm = RESOURCE__USE_NOIOMMU; - if (iommu_enabled) + if ( is_iommu_enabled(d) ) perm = ( iommu_intremap ? RESOURCE__USE_IOMMU : RESOURCE__USE_IOMMU_NOINTREMAP ); return perm; @@ -907,7 +907,7 @@ static int flask_map_domain_irq (struct domain *d, int irq, const void *data) u32 sid, dsid; int rc = -EPERM; struct avc_audit_data ad; - u32 dperm = flask_iommu_resource_use_perm(); + u32 dperm = flask_iommu_resource_use_perm(d); if ( irq >= nr_static_irqs && data ) { rc = flask_map_domain_msi(d, irq, data, &sid, &ad); @@ -973,7 +973,7 @@ static int flask_bind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *b int rc = -EPERM; int irq; struct avc_audit_data ad; - u32 dperm = flask_iommu_resource_use_perm(); + u32 dperm = flask_iommu_resource_use_perm(d); rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD); if ( rc ) @@ -1046,7 +1046,7 @@ static int flask_iomem_permission(struct domain *d, uint64_t start, uint64_t end data.ssid = domain_sid(current->domain); data.dsid = domain_sid(d); - data.use_perm = flask_iommu_resource_use_perm(); + data.use_perm = flask_iommu_resource_use_perm(d); return security_iterate_iomem_sids(start, end, _iomem_has_perm, &data); } @@ -1071,7 +1071,7 @@ static int flask_pci_config_permission(struct domain *d, uint32_t machine_bdf, u if ( access && (end >= 0x10 && start < 0x28) ) perm = RESOURCE__SETUP; else - perm = flask_iommu_resource_use_perm(); + perm = flask_iommu_resource_use_perm(d); AVC_AUDIT_DATA_INIT(&ad, DEV); ad.device = (unsigned long) machine_bdf; @@ -1296,7 +1296,7 @@ static int flask_assign_device(struct domain *d, uint32_t machine_bdf) u32 dsid, rsid; int rc = -EPERM; struct avc_audit_data ad; - u32 dperm = flask_iommu_resource_use_perm(); + u32 dperm = flask_iommu_resource_use_perm(d); if ( !d ) return flask_test_assign_device(machine_bdf); @@ -1355,7 +1355,7 @@ static int flask_assign_dtdevice(struct domain *d, const char *dtpath) u32 dsid, rsid; int rc = -EPERM; struct avc_audit_data ad; - u32 dperm = flask_iommu_resource_use_perm(); + u32 dperm = flask_iommu_resource_use_perm(d); if ( !d ) return flask_test_assign_dtdevice(dtpath); @@ -1540,7 +1540,7 @@ static int flask_ioport_permission(struct domain *d, uint32_t start, uint32_t en data.ssid = domain_sid(current->domain); data.dsid = domain_sid(d); - data.use_perm = flask_iommu_resource_use_perm(); + data.use_perm = flask_iommu_resource_use_perm(d); return security_iterate_ioport_sids(start, end, _ioport_has_perm, &data); } From patchwork Fri Sep 13 09:47:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11144293 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 787D2912 for ; Fri, 13 Sep 2019 09:49:24 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4740520717 for ; Fri, 13 Sep 2019 09:49:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=citrix.com header.i=@citrix.com header.b="B1pkQRD4" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4740520717 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=citrix.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBK-0002GW-64; Fri, 13 Sep 2019 09:47:58 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBI-0002FB-Iz for xen-devel@lists.xenproject.org; Fri, 13 Sep 2019 09:47:56 +0000 X-Inumbo-ID: 8af63b62-d60b-11e9-a337-bc764e2007e4 Received: from esa3.hc3370-68.iphmx.com (unknown [216.71.145.155]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 8af63b62-d60b-11e9-a337-bc764e2007e4; Fri, 13 Sep 2019 09:47:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1568368068; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=fgoZLPrXZJnKRh1u8ZJ6ZzZF9exZGd7aGvwLwgUkfZU=; b=B1pkQRD49U3c0geh4cQLIo5ihs7QoKJXGjcPHc2G6CuW4Cz4okS0KRfC 92nI2zUc33iHKm0xO7cYrYI1RaSOkyQRGMGuUzK5NQtcDmv2B70RuZq9k WQr0s0k89ZDh5gx7E38EFYJF6UNJ+NY1F1p6Mfy1JMn3F/dBZWdN0XKbD M=; Authentication-Results: esa3.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=paul.durrant@citrix.com; spf=Pass smtp.mailfrom=Paul.Durrant@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of paul.durrant@citrix.com) identity=pra; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="paul.durrant@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa3.hc3370-68.iphmx.com: domain of Paul.Durrant@citrix.com designates 162.221.158.21 as permitted sender) identity=mailfrom; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="Paul.Durrant@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:162.221.158.21 ip4:162.221.156.83 ~all" Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: vxyJwyRp6Rc6K+Czwh7XatPkvyUCu+eT2ReLlltwdHb/wPQKWD99gJULGH8pQhFAWEVAD7WlQl nQnWLAPRZxlloJ5HIpeJ4kOyhM0iSsmG0u6NmJU0ZOg6zf/3+LAWfTx6/ngv12t0X8UcXNx04S wExtCyO+p4htiQ3M6vCgHHU6W/CjEYsu0q+IbS7DMDK5pTPrkwNwGNB5k/sbv4HBWnSTmBZatU qXlytDz+3c6SQehUc2rNK1B+/uVTdXaG86pWpe6UGMe+EP0FQ3TUwr3cotOejNAUHmpCzTkzu1 CKQ= X-SBRS: 2.7 X-MesageID: 5528290 X-Ironport-Server: esa3.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.64,500,1559534400"; d="scan'208";a="5528290" From: Paul Durrant To: Date: Fri, 13 Sep 2019 10:47:38 +0100 Message-ID: <20190913094741.31451-4-paul.durrant@citrix.com> X-Mailer: git-send-email 2.20.1.2.gb21ebb671 In-Reply-To: <20190913094741.31451-1-paul.durrant@citrix.com> References: <20190913094741.31451-1-paul.durrant@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH v10 3/6] sysctl / libxl: report whether IOMMU/HAP page table sharing is supported X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Kevin Tian , Stefano Stabellini , Suravee Suthikulpanit , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ian Jackson , Tim Deegan , Julien Grall , Paul Durrant , Christian Lindig , Jan Beulich , David Scott , Anthony PERARD , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" This patch defines a new bit reported in the hw_cap field of struct xen_sysctl_physinfo to indicate whether the platform supports sharing of HAP page tables (i.e. the P2M) with the IOMMU. This informs the toolstack whether the domain needs extra memory to store discrete IOMMU page tables or not. NOTE: This patch makes sure iommu_hap_pt_shared is clear if HAP is not supported or the IOMMU is disabled, and defines it to false if !CONFIG_HVM. Signed-off-by: Paul Durrant Acked-by: Christian Lindig Acked-by: Wei Liu --- Cc: Ian Jackson Cc: Wei Liu Cc: Anthony PERARD Cc: Andrew Cooper Cc: George Dunlap Cc: Jan Beulich Cc: Julien Grall Cc: Konrad Rzeszutek Wilk Cc: Stefano Stabellini Cc: Tim Deegan Cc: Christian Lindig Cc: David Scott Cc: "Roger Pau Monné" Cc: Suravee Suthikulpanit Cc: Kevin Tian v10: - Set flag in common code (which means clearing iommu_hap_pt_share if HAP cannot be enabled or is configured out). v9: - New in v9 --- tools/libxl/libxl.c | 2 ++ tools/libxl/libxl.h | 7 +++++++ tools/libxl/libxl_types.idl | 1 + tools/ocaml/libs/xc/xenctrl.ml | 1 + tools/ocaml/libs/xc/xenctrl.mli | 3 ++- tools/xl/xl_info.c | 5 +++-- xen/arch/x86/hvm/hvm.c | 25 +++++++++++++++++------- xen/common/sysctl.c | 2 ++ xen/drivers/passthrough/amd/iommu_init.c | 5 ++++- xen/drivers/passthrough/iommu.c | 18 ++++++++++++++++- xen/drivers/passthrough/vtd/iommu.c | 6 +++++- xen/include/public/sysctl.h | 6 +++++- xen/include/xen/iommu.h | 8 +++++++- 13 files changed, 74 insertions(+), 15 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 57073c06d5..a0d84281d0 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -402,6 +402,8 @@ int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo) physinfo->cap_hap = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_hap); physinfo->cap_shadow = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_shadow); + physinfo->cap_iommu_hap_pt_share = + !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_iommu_hap_pt_share); GC_FREE; return 0; diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 466df2cdf5..8169d44bda 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -401,6 +401,13 @@ */ #define LIBXL_HAVE_PHYSINFO_CAP_HAP_SHADOW 1 +/* + * LIBXL_HAVE_PHYSINFO_CAP_IOMMU_HAP_PT_SHARE indicates that libxl_physinfo + * has a cap_iommu_hap_pt_share field that indicates whether the hardware + * supports sharing the IOMMU and HAP page tables. + */ +#define LIBXL_HAVE_PHYSINFO_CAP_IOMMU_HAP_PT_SHARE 1 + /* * libxl ABI compatibility * diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 6f431baec2..7253d6e0fb 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -1027,6 +1027,7 @@ libxl_physinfo = Struct("physinfo", [ ("cap_hvm_directio", bool), # No longer HVM specific ("cap_hap", bool), ("cap_shadow", bool), + ("cap_iommu_hap_pt_share", bool), ], dir=DIR_OUT) libxl_connectorinfo = Struct("connectorinfo", [ diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml index 35dddbbd9c..de4bae6012 100644 --- a/tools/ocaml/libs/xc/xenctrl.ml +++ b/tools/ocaml/libs/xc/xenctrl.ml @@ -110,6 +110,7 @@ type physinfo_cap_flag = | CAP_DirectIO | CAP_HAP | CAP_Shadow + | CAP_IOMMU_HAP_PT_SHARE type physinfo = { diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli index 0dd55e9d8b..c885e75895 100644 --- a/tools/ocaml/libs/xc/xenctrl.mli +++ b/tools/ocaml/libs/xc/xenctrl.mli @@ -57,7 +57,6 @@ type domain_create_flag = | CDF_OOS_OFF | CDF_XS_DOMAIN | CDF_IOMMU - type domctl_create_config = { ssidref: int32; handle: string; @@ -95,6 +94,8 @@ type physinfo_cap_flag = | CAP_DirectIO | CAP_HAP | CAP_Shadow + | CAP_IOMMU_HAP_PT_SHARE + type physinfo = { threads_per_core : int; cores_per_socket : int; diff --git a/tools/xl/xl_info.c b/tools/xl/xl_info.c index 148c4740ae..bfbca93997 100644 --- a/tools/xl/xl_info.c +++ b/tools/xl/xl_info.c @@ -210,13 +210,14 @@ static void output_physinfo(void) info.hw_cap[4], info.hw_cap[5], info.hw_cap[6], info.hw_cap[7] ); - maybe_printf("virt_caps :%s%s%s%s%s%s\n", + maybe_printf("virt_caps :%s%s%s%s%s%s%s\n", info.cap_pv ? " pv" : "", info.cap_hvm ? " hvm" : "", info.cap_hvm && info.cap_hvm_directio ? " hvm_directio" : "", info.cap_pv && info.cap_hvm_directio ? " pv_directio" : "", info.cap_hap ? " hap" : "", - info.cap_shadow ? " shadow" : "" + info.cap_shadow ? " shadow" : "", + info.cap_iommu_hap_pt_share ? " iommu_hap_pt_share" : "" ); vinfo = libxl_get_version_info(ctx); diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 3831c6d4c1..ed8272cf93 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -142,6 +142,22 @@ static struct notifier_block cpu_nfb = { .notifier_call = cpu_callback }; +static bool __init hap_supported(const struct hvm_function_table *fns) +{ + if ( !fns->hap_supported ) + { + printk("HVM: Hardware Assisted Paging (HAP) not detected\n"); + return false; + } + else if ( !opt_hap_enabled ) + { + printk("HVM: Hardware Assisted Paging (HAP) detected but disabled\n"); + return false; + } + + return true; +} + static int __init hvm_enable(void) { const struct hvm_function_table *fns = NULL; @@ -158,13 +174,8 @@ static int __init hvm_enable(void) hvm_enabled = 1; printk("HVM: %s enabled\n", fns->name); - if ( !fns->hap_supported ) - printk("HVM: Hardware Assisted Paging (HAP) not detected\n"); - else if ( !opt_hap_enabled ) - { - hvm_funcs.hap_supported = 0; - printk("HVM: Hardware Assisted Paging (HAP) detected but disabled\n"); - } + if ( !hap_supported(fns) ) + iommu_hap_pt_share = false; else { printk("HVM: Hardware Assisted Paging (HAP) detected\n"); diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index 92b4ea0d21..ef840fcb76 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -269,6 +269,8 @@ long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl) arch_do_physinfo(pi); if ( iommu_enabled ) pi->capabilities |= XEN_SYSCTL_PHYSCAP_directio; + if ( iommu_hap_pt_share ) + pi->capabilities |= XEN_SYSCTL_PHYSCAP_iommu_hap_pt_share; if ( copy_to_guest(u_sysctl, op, 1) ) ret = -EFAULT; diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c index bb5a3e57c9..2e011d4e43 100644 --- a/xen/drivers/passthrough/amd/iommu_init.c +++ b/xen/drivers/passthrough/amd/iommu_init.c @@ -1401,12 +1401,15 @@ int __init amd_iommu_init(bool xt) if ( rc ) goto error_out; +#ifndef iommu_hap_pt_share /* * Disable sharing HAP page tables with AMD IOMMU, * since it only supports p2m_ram_rw, and this would * prevent doing IO to/from mapped grant frames. */ - iommu_hap_pt_share = 0; + iommu_hap_pt_share = false; +#endif + printk(XENLOG_DEBUG "AMD-Vi: Disabled HAP memory map sharing with IOMMU\n"); /* per iommu initialization */ diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index 09ce9d9294..bdf12f85e6 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -49,7 +49,11 @@ int8_t __hwdom_initdata iommu_hwdom_reserved = -1; * default until we find a good solution to resolve it. */ bool_t __read_mostly iommu_intpost; -bool_t __read_mostly iommu_hap_pt_share = 1; + +#ifndef iommu_hap_pt_share +bool __read_mostly iommu_hap_pt_share = true; +#endif + bool_t __read_mostly iommu_debug; bool_t __read_mostly amd_iommu_perdev_intremap = 1; @@ -103,7 +107,14 @@ static int __init parse_iommu_param(const char *s) else if ( (val = parse_boolean("dom0-strict", s, ss)) >= 0 ) iommu_hwdom_strict = val; else if ( (val = parse_boolean("sharept", s, ss)) >= 0 ) + { +#ifndef iommu_hap_pt_share iommu_hap_pt_share = val; +#else + if (val != iommu_hap_pt_share) + rc = -EINVAL; +#endif + } else rc = -EINVAL; @@ -511,7 +522,12 @@ int __init iommu_setup(void) iommu_enabled = (rc == 0); } if ( !iommu_enabled ) + { iommu_intremap = 0; +#ifndef iommu_hap_pt_share + iommu_hap_pt_share = false; +#endif + } if ( (force_iommu && !iommu_enabled) || (force_intremap && !iommu_intremap) ) diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 7ffafdc065..a7381a7449 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -1898,6 +1898,7 @@ int iommu_pte_flush(struct domain *d, uint64_t dfn, uint64_t *pte, return rc; } +#ifndef iommu_hap_pt_share static int __init vtd_ept_page_compatible(struct vtd_iommu *iommu) { u64 ept_cap, vtd_cap = iommu->cap; @@ -1910,6 +1911,7 @@ static int __init vtd_ept_page_compatible(struct vtd_iommu *iommu) return (ept_has_2mb(ept_cap) && opt_hap_2mb) == cap_sps_2mb(vtd_cap) && (ept_has_1gb(ept_cap) && opt_hap_1gb) == cap_sps_1gb(vtd_cap); } +#endif /* * set VT-d page table directory to EPT table if allowed @@ -2309,8 +2311,10 @@ static int __init vtd_setup(void) if ( !cap_intr_post(iommu->cap) || !iommu_intremap || !cpu_has_cx16 ) iommu_intpost = 0; +#ifndef iommu_hap_pt_share if ( !vtd_ept_page_compatible(iommu) ) - iommu_hap_pt_share = 0; + iommu_hap_pt_share = false; +#endif ret = iommu_set_interrupt(drhd); if ( ret ) diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index e324442f92..2be013de5b 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -96,9 +96,13 @@ struct xen_sysctl_tbuf_op { /* The platform supports software paging. */ #define _XEN_SYSCTL_PHYSCAP_shadow 4 #define XEN_SYSCTL_PHYSCAP_shadow (1u<<_XEN_SYSCTL_PHYSCAP_shadow) +/* The platform supports sharing of HAP page tables with the IOMMU. */ +#define _XEN_SYSCTL_PHYSCAP_iommu_hap_pt_share 5 +#define XEN_SYSCTL_PHYSCAP_iommu_hap_pt_share \ + (1u << _XEN_SYSCTL_PHYSCAP_iommu_hap_pt_share) /* Max XEN_SYSCTL_PHYSCAP_* constant. Used for ABI checking. */ -#define XEN_SYSCTL_PHYSCAP_MAX XEN_SYSCTL_PHYSCAP_shadow +#define XEN_SYSCTL_PHYSCAP_MAX XEN_SYSCTL_PHYSCAP_hap_pt_share struct xen_sysctl_physinfo { uint32_t threads_per_core; diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index ab258b848b..a519f4d87b 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -55,7 +55,13 @@ static inline bool_t dfn_eq(dfn_t x, dfn_t y) extern bool_t iommu_enable, iommu_enabled; extern bool_t force_iommu, iommu_verbose, iommu_igfx; extern bool_t iommu_snoop, iommu_qinval, iommu_intremap, iommu_intpost; -extern bool_t iommu_hap_pt_share; + +#ifdef CONFIG_HVM +extern bool iommu_hap_pt_share; +#else +#define iommu_hap_pt_share false +#endif + extern bool_t iommu_debug; extern bool_t amd_iommu_perdev_intremap; From patchwork Fri Sep 13 09:47:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11144303 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3FB9D912 for ; Fri, 13 Sep 2019 09:49:56 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 04FF620717 for ; Fri, 13 Sep 2019 09:49:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=citrix.com header.i=@citrix.com header.b="WQy6GO0S" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 04FF620717 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=citrix.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBI-0002FE-Mw; Fri, 13 Sep 2019 09:47:56 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBH-0002Ey-RO for xen-devel@lists.xenproject.org; Fri, 13 Sep 2019 09:47:55 +0000 X-Inumbo-ID: 8d503354-d60b-11e9-95aa-12813bfff9fa Received: from esa6.hc3370-68.iphmx.com (unknown [216.71.155.175]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 8d503354-d60b-11e9-95aa-12813bfff9fa; Fri, 13 Sep 2019 09:47:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1568368072; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=gg5e0IIt/zV/jbr8zlHtiZflCalkuL5ls2JJUj2Ps2M=; b=WQy6GO0S9+cAWlVxyD66ReLJIqDhyvkmu68n3nszrUb52Od7qJe8yQ+v cUWM8S25Lh3dcRkjKIoWgNwlO7unxC7oEOPWZgH/bL9XtTEckB8KAKo4Z l8YlaeCfJIy1qHnLpWNJX/XlTRHIA7c8vSw+IS1J7wcXpxlqZNheF3bID o=; Authentication-Results: esa6.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=paul.durrant@citrix.com; spf=Pass smtp.mailfrom=Paul.Durrant@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: None (esa6.hc3370-68.iphmx.com: no sender authenticity information available from domain of paul.durrant@citrix.com) identity=pra; client-ip=162.221.158.21; receiver=esa6.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="paul.durrant@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa6.hc3370-68.iphmx.com: domain of Paul.Durrant@citrix.com designates 162.221.158.21 as permitted sender) identity=mailfrom; client-ip=162.221.158.21; receiver=esa6.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="Paul.Durrant@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:162.221.158.21 ip4:162.221.156.83 ~all" Received-SPF: None (esa6.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=162.221.158.21; receiver=esa6.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: iq8OiaoKhOgttYdOKZeYc3mQFA9J4VDJ4fcg3JgpjWoOUZCSI07LJWu9JoDfURuvTF+2QkDalW gdbyt7BVOliuRlBeD6qbR4iUG6lpChOea0HtVcC93KMKWjIFhlovkkvU8kjBz349XsPH1SUOF/ 0VnM8raujh8gcv4pE1LcXLalAZui8jym0cjXy3518duOXckudEdXfS/gJi9rLwUaIE1EJf6JTm E/10l5WsDV4iwEb9dugSoDxmD0exO1MzODJSZsBuvqoQOPj6ElPcgnQUgfuJDH2iGOw9Neq6XM Lak= X-SBRS: 2.7 X-MesageID: 5772424 X-Ironport-Server: esa6.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.64,500,1559534400"; d="scan'208";a="5772424" From: Paul Durrant To: Date: Fri, 13 Sep 2019 10:47:39 +0100 Message-ID: <20190913094741.31451-5-paul.durrant@citrix.com> X-Mailer: git-send-email 2.20.1.2.gb21ebb671 In-Reply-To: <20190913094741.31451-1-paul.durrant@citrix.com> References: <20190913094741.31451-1-paul.durrant@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH v10 4/6] remove late (on-demand) construction of IOMMU page tables X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Petre Pircalabu , Stefano Stabellini , Wei Liu , Razvan Cojocaru , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ian Jackson , Tim Deegan , Julien Grall , Paul Durrant , Tamas K Lengyel , Jan Beulich , Alexandru Isaila , Volodymyr Babchuk , =?utf-8?q?Roger_Pau_Monn?= =?utf-8?q?=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" Now that there is a per-domain IOMMU-enable flag, which should be set if any device is going to be passed through, stop deferring page table construction until the assignment is done. Also don't tear down the tables again when the last device is de-assigned; defer that task until domain destruction. This allows the has_iommu_pt() helper and iommu_status enumeration to be removed. Calls to has_iommu_pt() are simply replaced by calls to is_iommu_enabled(). Remaining open-coded tests of iommu_hap_pt_share can also be replaced by calls to iommu_use_hap_pt(). The arch_iommu_populate_page_table() and iommu_construct() functions become redundant, as does the 'strict mode' dom0 page_list mapping code in iommu_hwdom_init(), and iommu_teardown() can be made static is its only remaining caller, iommu_domain_destroy(), is within the same source module. All in all, about 220 lines of code are removed from the hypervisor (at the expense of some additions in the toolstack). NOTE: This patch will cause a small amount of extra resource to be used to accommodate IOMMU page tables that may never be used, since the per-domain IOMMU-enable flag is currently set to the value of the global iommu_enable flag. A subsequent patch will add an option to the toolstack to allow it to be turned off if there is no intention to assign passthrough hardware to the domain. To account for the extra resource, 'iommu_memkb' has been added to domain_build_info. This patch sets it to a value calculated based on the domain's maximum memory when the P2M sharing is either not supported or globally disabled, or zero otherwise. However, when the toolstack option mentioned above is added, it will also be zero if the per-domain IOMMU-enable flag is turned off. Signed-off-by: Paul Durrant Reviewed-by: Alexandru Isaila Acked-by: Razvan Cojocaru Reviewed-by: Jan Beulich --- Cc: Stefano Stabellini Cc: Julien Grall Cc: Volodymyr Babchuk Cc: Andrew Cooper Cc: George Dunlap Cc: Ian Jackson Cc: Konrad Rzeszutek Wilk Cc: Tim Deegan Cc: Wei Liu Cc: "Roger Pau Monné" Cc: Tamas K Lengyel Cc: George Dunlap Cc: Petre Pircalabu Previously part of series https://lists.xenproject.org/archives/html/xen-devel/2019-07/msg02267.html v9: - Avoid the iommu_memkb overhead if the IOMMU is disable or page tables are shared v7: - Add toolstack memory reservation for IOMMU page tables... Re-use of shadow calculation didn't seem appropriate so a new helper function is added v5: - Minor style fixes --- tools/libxl/libxl.h | 7 ++ tools/libxl/libxl_mem.c | 6 +- tools/libxl/libxl_types.idl | 1 + tools/libxl/libxl_utils.c | 15 +++ tools/libxl/libxl_utils.h | 1 + tools/xl/xl_parse.c | 24 ++++- xen/arch/arm/p2m.c | 2 +- xen/arch/x86/dom0_build.c | 2 +- xen/arch/x86/hvm/mtrr.c | 5 +- xen/arch/x86/mm/mem_sharing.c | 2 +- xen/arch/x86/mm/p2m.c | 4 +- xen/arch/x86/mm/paging.c | 2 +- xen/arch/x86/x86_64/mm.c | 2 +- xen/common/memory.c | 4 +- xen/common/vm_event.c | 2 +- xen/drivers/passthrough/device_tree.c | 11 --- xen/drivers/passthrough/iommu.c | 134 ++++++-------------------- xen/drivers/passthrough/pci.c | 12 --- xen/drivers/passthrough/vtd/iommu.c | 10 +- xen/drivers/passthrough/x86/iommu.c | 97 ------------------- xen/include/asm-arm/iommu.h | 2 +- xen/include/asm-x86/iommu.h | 2 +- xen/include/xen/iommu.h | 16 --- xen/include/xen/sched.h | 2 - 24 files changed, 94 insertions(+), 271 deletions(-) diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 8169d44bda..12545130df 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -408,6 +408,13 @@ */ #define LIBXL_HAVE_PHYSINFO_CAP_IOMMU_HAP_PT_SHARE 1 +/* + * LIBXL_HAVE_BUILDINFO_IOMMU_MEMKB indicates thate libxl_domain_build_info + * has an iommu_memkb field which should be set with the amount of memory + * overhead needed by the domain for populating IOMMU page tables. + */ +#define LIBXL_HAVE_BUILDINFO_IOMMU_MEMKB 1 + /* * libxl ABI compatibility * diff --git a/tools/libxl/libxl_mem.c b/tools/libxl/libxl_mem.c index 448a2af8fd..fd6f33312e 100644 --- a/tools/libxl/libxl_mem.c +++ b/tools/libxl/libxl_mem.c @@ -461,15 +461,17 @@ int libxl_domain_need_memory(libxl_ctx *ctx, if (rc) goto out; *need_memkb = b_info->target_memkb; + *need_memkb += b_info->shadow_memkb + b_info->iommu_memkb; + switch (b_info->type) { case LIBXL_DOMAIN_TYPE_PVH: case LIBXL_DOMAIN_TYPE_HVM: - *need_memkb += b_info->shadow_memkb + LIBXL_HVM_EXTRA_MEMORY; + *need_memkb += LIBXL_HVM_EXTRA_MEMORY; if (libxl_defbool_val(b_info->device_model_stubdomain)) *need_memkb += 32 * 1024; break; case LIBXL_DOMAIN_TYPE_PV: - *need_memkb += b_info->shadow_memkb + LIBXL_PV_EXTRA_MEMORY; + *need_memkb += LIBXL_PV_EXTRA_MEMORY; break; default: rc = ERROR_INVAL; diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 7253d6e0fb..d52c63b6b0 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -486,6 +486,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("target_memkb", MemKB), ("video_memkb", MemKB), ("shadow_memkb", MemKB), + ("iommu_memkb", MemKB), ("rtc_timeoffset", uint32), ("exec_ssidref", uint32), ("exec_ssid_label", string), diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index f360f5e228..405733b7e1 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -48,6 +48,21 @@ unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned return 4 * (256 * smp_cpus + 2 * (maxmem_kb / 1024)); } +unsigned long libxl_get_required_iommu_memory(unsigned long maxmem_kb) +{ + unsigned long iommu_pages = 0, mem_pages = maxmem_kb / 4; + unsigned int level; + + /* Assume a 4 level page table with 512 entries per level */ + for (level = 0; level < 4; level++) + { + mem_pages = DIV_ROUNDUP(mem_pages, 512); + iommu_pages += mem_pages; + } + + return iommu_pages * 4; +} + char *libxl_domid_to_name(libxl_ctx *ctx, uint32_t domid) { unsigned int len; diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h index 44409afdc4..630ccbe28a 100644 --- a/tools/libxl/libxl_utils.h +++ b/tools/libxl/libxl_utils.h @@ -24,6 +24,7 @@ const char *libxl_basename(const char *name); /* returns string from strdup */ unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus); +unsigned long libxl_get_required_iommu_memory(unsigned long maxmem_kb); int libxl_name_to_domid(libxl_ctx *ctx, const char *name, uint32_t *domid); int libxl_domain_qualifier_to_domid(libxl_ctx *ctx, const char *name, uint32_t *domid); char *libxl_domid_to_name(libxl_ctx *ctx, uint32_t domid); diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c index e105bda2bb..293f5f730e 100644 --- a/tools/xl/xl_parse.c +++ b/tools/xl/xl_parse.c @@ -1207,6 +1207,7 @@ void parse_config_data(const char *config_source, int config_len, libxl_domain_config *d_config) { + libxl_physinfo physinfo; const char *buf; long l, vcpus = 0; XLU_Config *config; @@ -1221,10 +1222,22 @@ void parse_config_data(const char *config_source, int pci_seize = 0; int i, e; char *kernel_basename; + bool iommu_enabled, iommu_hap_pt_share; libxl_domain_create_info *c_info = &d_config->c_info; libxl_domain_build_info *b_info = &d_config->b_info; + libxl_physinfo_init(&physinfo); + if (libxl_get_physinfo(ctx, &physinfo) != 0) { + libxl_physinfo_dispose(&physinfo); + fprintf(stderr, "libxl_get_physinfo failed\n"); + exit(EXIT_FAILURE); + } + + iommu_enabled = physinfo.cap_hvm_directio; + iommu_hap_pt_share = physinfo.cap_iommu_hap_pt_share; + libxl_physinfo_dispose(&physinfo); + config= xlu_cfg_init(stderr, config_source); if (!config) { fprintf(stderr, "Failed to allocate for configuration\n"); @@ -1448,14 +1461,21 @@ void parse_config_data(const char *config_source, exit(1); } - /* libxl_get_required_shadow_memory() must be called after final values + /* libxl_get_required_shadow_memory() and + * libxl_get_required_iommu_memory() must be called after final values * (default or specified) for vcpus and memory are set, because the - * calculation depends on those values. */ + * calculations depend on those values. */ b_info->shadow_memkb = !xlu_cfg_get_long(config, "shadow_memory", &l, 0) ? l * 1024 : libxl_get_required_shadow_memory(b_info->max_memkb, b_info->max_vcpus); + /* No IOMMU reservation is needed if either the IOMMU is disabled or it + * can share the P2M. */ + b_info->iommu_memkb = (!iommu_enabled || iommu_hap_pt_share) + ? 0 + : libxl_get_required_iommu_memory(b_info->max_memkb); + xlu_cfg_get_defbool(config, "nomigrate", &b_info->disable_migrate, 0); if (!xlu_cfg_get_long(config, "tsc_mode", &l, 1)) { diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index 7f1442932a..692565757e 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -1056,7 +1056,7 @@ static int __p2m_set_entry(struct p2m_domain *p2m, !mfn_eq(lpae_get_mfn(*entry), lpae_get_mfn(orig_pte)) ) p2m_free_entry(p2m, orig_pte, level); - if ( has_iommu_pt(p2m->domain) && + if ( is_iommu_enabled(p2m->domain) && (lpae_is_valid(orig_pte) || lpae_is_valid(*entry)) ) { unsigned int flush_flags = 0; diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index d381784edd..7cfab2dc25 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -365,7 +365,7 @@ unsigned long __init dom0_compute_nr_pages( } need_paging = is_hvm_domain(d) && - (!iommu_hap_pt_share || !paging_mode_hap(d)); + (!iommu_use_hap_pt(d) || !paging_mode_hap(d)); for ( ; ; need_paging = false ) { nr_pages = get_memsize(&dom0_size, avail); diff --git a/xen/arch/x86/hvm/mtrr.c b/xen/arch/x86/hvm/mtrr.c index 7ccd85bcea..5ad15eafe0 100644 --- a/xen/arch/x86/hvm/mtrr.c +++ b/xen/arch/x86/hvm/mtrr.c @@ -783,7 +783,8 @@ HVM_REGISTER_SAVE_RESTORE(MTRR, hvm_save_mtrr_msr, hvm_load_mtrr_msr, 1, void memory_type_changed(struct domain *d) { - if ( (has_iommu_pt(d) || cache_flush_permitted(d)) && d->vcpu && d->vcpu[0] ) + if ( (is_iommu_enabled(d) || cache_flush_permitted(d)) && + d->vcpu && d->vcpu[0] ) { p2m_memory_type_changed(d); flush_all(FLUSH_CACHE); @@ -831,7 +832,7 @@ int epte_get_entry_emt(struct domain *d, unsigned long gfn, mfn_t mfn, return MTRR_TYPE_UNCACHABLE; } - if ( !has_iommu_pt(d) && !cache_flush_permitted(d) ) + if ( !is_iommu_enabled(d) && !cache_flush_permitted(d) ) { *ipat = 1; return MTRR_TYPE_WRBACK; diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index a5fe89e339..efb8821768 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -1664,7 +1664,7 @@ int mem_sharing_domctl(struct domain *d, struct xen_domctl_mem_sharing_op *mec) case XEN_DOMCTL_MEM_SHARING_CONTROL: { rc = 0; - if ( unlikely(has_iommu_pt(d) && mec->u.enable) ) + if ( unlikely(is_iommu_enabled(d) && mec->u.enable) ) rc = -EXDEV; else d->arch.hvm.mem_sharing_enabled = mec->u.enable; diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 8a5229ee21..e5e4349dea 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -1341,7 +1341,7 @@ int set_identity_p2m_entry(struct domain *d, unsigned long gfn_l, if ( !paging_mode_translate(p2m->domain) ) { - if ( !has_iommu_pt(d) ) + if ( !is_iommu_enabled(d) ) return 0; return iommu_legacy_map(d, _dfn(gfn_l), _mfn(gfn_l), PAGE_ORDER_4K, IOMMUF_readable | IOMMUF_writable); @@ -1432,7 +1432,7 @@ int clear_identity_p2m_entry(struct domain *d, unsigned long gfn_l) if ( !paging_mode_translate(d) ) { - if ( !has_iommu_pt(d) ) + if ( !is_iommu_enabled(d) ) return 0; return iommu_legacy_unmap(d, _dfn(gfn_l), PAGE_ORDER_4K); } diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c index 69aa228e46..d9a52c4db4 100644 --- a/xen/arch/x86/mm/paging.c +++ b/xen/arch/x86/mm/paging.c @@ -213,7 +213,7 @@ int paging_log_dirty_enable(struct domain *d, bool_t log_global) { int ret; - if ( has_iommu_pt(d) && log_global ) + if ( is_iommu_enabled(d) && log_global ) { /* * Refuse to turn on global log-dirty mode diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index 795a467462..fa55f3474e 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -1434,7 +1434,7 @@ int memory_add(unsigned long spfn, unsigned long epfn, unsigned int pxm) * shared or being kept in sync then newly added memory needs to be * mapped here. */ - if ( has_iommu_pt(hardware_domain) && + if ( is_iommu_enabled(hardware_domain) && !iommu_use_hap_pt(hardware_domain) && !need_iommu_pt_sync(hardware_domain) ) { diff --git a/xen/common/memory.c b/xen/common/memory.c index d5aff83f2d..7364fd2c33 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -823,7 +823,7 @@ int xenmem_add_to_physmap(struct domain *d, struct xen_add_to_physmap *xatp, xatp->gpfn += start; xatp->size -= start; - if ( has_iommu_pt(d) ) + if ( is_iommu_enabled(d) ) this_cpu(iommu_dont_flush_iotlb) = 1; while ( xatp->size > done ) @@ -844,7 +844,7 @@ int xenmem_add_to_physmap(struct domain *d, struct xen_add_to_physmap *xatp, } } - if ( has_iommu_pt(d) ) + if ( is_iommu_enabled(d) ) { int ret; diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c index 2a1c87e44b..3b18195ebf 100644 --- a/xen/common/vm_event.c +++ b/xen/common/vm_event.c @@ -630,7 +630,7 @@ int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec) /* No paging if iommu is used */ rc = -EMLINK; - if ( unlikely(has_iommu_pt(d)) ) + if ( unlikely(is_iommu_enabled(d)) ) break; rc = -EXDEV; diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c index 12f2c4c3f2..ea9fd54e3b 100644 --- a/xen/drivers/passthrough/device_tree.c +++ b/xen/drivers/passthrough/device_tree.c @@ -40,17 +40,6 @@ int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev) if ( !list_empty(&dev->domain_list) ) goto fail; - /* - * The hwdom is forced to use IOMMU for protecting assigned - * device. Therefore the IOMMU data is already set up. - */ - ASSERT(!is_hardware_domain(d) || - hd->status == IOMMU_STATUS_initialized); - - rc = iommu_construct(d); - if ( rc ) - goto fail; - /* The flag field doesn't matter to DT device. */ rc = hd->platform_ops->assign_device(d, 0, dt_to_dev(dev), 0); diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index bdf12f85e6..a49346394d 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -157,6 +157,17 @@ static int __init parse_dom0_iommu_param(const char *s) } custom_param("dom0-iommu", parse_dom0_iommu_param); +static void __hwdom_init check_hwdom_reqs(struct domain *d) +{ + if ( iommu_hwdom_none || !paging_mode_translate(d) ) + return; + + arch_iommu_check_autotranslated_hwdom(d); + + iommu_hwdom_passthrough = false; + iommu_hwdom_strict = true; +} + int iommu_domain_init(struct domain *d) { struct domain_iommu *hd = dom_iommu(d); @@ -174,129 +185,44 @@ int iommu_domain_init(struct domain *d) return ret; hd->platform_ops = iommu_get_ops(); - return hd->platform_ops->init(d); -} + ret = hd->platform_ops->init(d); + if ( ret ) + return ret; -static void __hwdom_init check_hwdom_reqs(struct domain *d) -{ - if ( iommu_hwdom_none || !paging_mode_translate(d) ) - return; + if ( is_hardware_domain(d) ) + check_hwdom_reqs(d); /* may modify iommu_hwdom_strict */ - arch_iommu_check_autotranslated_hwdom(d); + /* + * NB: 'relaxed' h/w domains don't need the IOMMU mappings to be kept + * in-sync with their assigned pages because all host RAM will be + * mapped during hwdom_init(). + */ + if ( !is_hardware_domain(d) || iommu_hwdom_strict ) + hd->need_sync = !iommu_use_hap_pt(d); - iommu_hwdom_passthrough = false; - iommu_hwdom_strict = true; + return 0; } void __hwdom_init iommu_hwdom_init(struct domain *d) { struct domain_iommu *hd = dom_iommu(d); - check_hwdom_reqs(d); - if ( !is_iommu_enabled(d) ) return; register_keyhandler('o', &iommu_dump_p2m_table, "dump iommu p2m table", 0); - hd->status = IOMMU_STATUS_initializing; - /* - * NB: relaxed hw domains don't need sync because all ram is already - * mapped in the iommu page tables. - */ - hd->need_sync = iommu_hwdom_strict && !iommu_use_hap_pt(d); - if ( need_iommu_pt_sync(d) ) - { - struct page_info *page; - unsigned int i = 0, flush_flags = 0; - int rc = 0; - - page_list_for_each ( page, &d->page_list ) - { - unsigned long mfn = mfn_x(page_to_mfn(page)); - unsigned long dfn = mfn_to_gmfn(d, mfn); - unsigned int mapping = IOMMUF_readable; - int ret; - - if ( ((page->u.inuse.type_info & PGT_count_mask) == 0) || - ((page->u.inuse.type_info & PGT_type_mask) - == PGT_writable_page) ) - mapping |= IOMMUF_writable; - - ret = iommu_map(d, _dfn(dfn), _mfn(mfn), 0, mapping, - &flush_flags); - - if ( !rc ) - rc = ret; - - if ( !(i++ & 0xfffff) ) - process_pending_softirqs(); - } - - /* Use while-break to avoid compiler warning */ - while ( iommu_iotlb_flush_all(d, flush_flags) ) - break; - - if ( rc ) - printk(XENLOG_WARNING "d%d: IOMMU mapping failed: %d\n", - d->domain_id, rc); - } - hd->platform_ops->hwdom_init(d); - - hd->status = IOMMU_STATUS_initialized; } -void iommu_teardown(struct domain *d) +static void iommu_teardown(struct domain *d) { struct domain_iommu *hd = dom_iommu(d); - hd->status = IOMMU_STATUS_disabled; hd->platform_ops->teardown(d); tasklet_schedule(&iommu_pt_cleanup_tasklet); } -int iommu_construct(struct domain *d) -{ - struct domain_iommu *hd = dom_iommu(d); - - if ( hd->status == IOMMU_STATUS_initialized ) - return 0; - - hd->status = IOMMU_STATUS_initializing; - - if ( !iommu_use_hap_pt(d) ) - { - int rc; - - hd->need_sync = true; - - rc = arch_iommu_populate_page_table(d); - if ( rc ) - { - if ( rc != -ERESTART ) - { - hd->need_sync = false; - hd->status = IOMMU_STATUS_disabled; - } - - return rc; - } - } - - hd->status = IOMMU_STATUS_initialized; - - /* - * There may be dirty cache lines when a device is assigned - * and before has_iommu_pt(d) becoming true, this will cause - * memory_type_changed lose effect if memory type changes. - * Call memory_type_changed here to amend this. - */ - memory_type_changed(d); - - return 0; -} - void iommu_domain_destroy(struct domain *d) { if ( !is_iommu_enabled(d) ) @@ -594,11 +520,8 @@ int iommu_do_domctl( void iommu_share_p2m_table(struct domain* d) { ASSERT(hap_enabled(d)); - /* - * iommu_use_hap_pt(d) cannot be used here because during domain - * construction has_iommu_pt(d) will always return false here. - */ - if ( is_iommu_enabled(d) && iommu_hap_pt_share ) + + if ( iommu_use_hap_pt(d) ) iommu_get_ops()->share_p2m(d); } @@ -645,8 +568,7 @@ static void iommu_dump_p2m_table(unsigned char key) ops = iommu_get_ops(); for_each_domain(d) { - if ( is_hardware_domain(d) || - dom_iommu(d)->status < IOMMU_STATUS_initialized ) + if ( is_hardware_domain(d) || !is_iommu_enabled(d) ) continue; if ( iommu_use_hap_pt(d) ) diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index 814106679f..2315d490dc 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -933,9 +933,6 @@ static int deassign_device(struct domain *d, uint16_t seg, uint8_t bus, pdev->fault.count = 0; - if ( !has_arch_pdevs(d) && has_iommu_pt(d) ) - iommu_teardown(d); - return ret; } @@ -1484,13 +1481,6 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) if ( !pcidevs_trylock() ) return -ERESTART; - rc = iommu_construct(d); - if ( rc ) - { - pcidevs_unlock(); - return rc; - } - pdev = pci_get_pdev_by_domain(hardware_domain, seg, bus, devfn); if ( !pdev ) { @@ -1519,8 +1509,6 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) } done: - if ( !has_arch_pdevs(d) && has_iommu_pt(d) ) - iommu_teardown(d); pcidevs_unlock(); return rc; diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index a7381a7449..fa30ed697b 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -1721,15 +1721,7 @@ static void iommu_domain_teardown(struct domain *d) ASSERT(is_iommu_enabled(d)); - /* - * We can't use iommu_use_hap_pt here because either IOMMU state - * is already changed to IOMMU_STATUS_disabled at this point or - * has always been IOMMU_STATUS_disabled. - * - * We also need to test if HAP is enabled because PV guests can - * enter this path too. - */ - if ( hap_enabled(d) && iommu_hap_pt_share ) + if ( iommu_use_hap_pt(d) ) return; spin_lock(&hd->arch.mapping_lock); diff --git a/xen/drivers/passthrough/x86/iommu.c b/xen/drivers/passthrough/x86/iommu.c index 8319fe0a69..47a3e55213 100644 --- a/xen/drivers/passthrough/x86/iommu.c +++ b/xen/drivers/passthrough/x86/iommu.c @@ -81,103 +81,6 @@ int __init iommu_setup_hpet_msi(struct msi_desc *msi) return ops->setup_hpet_msi ? ops->setup_hpet_msi(msi) : -ENODEV; } -int arch_iommu_populate_page_table(struct domain *d) -{ - struct page_info *page; - int rc = 0, n = 0; - - spin_lock(&d->page_alloc_lock); - - if ( unlikely(d->is_dying) ) - rc = -ESRCH; - - while ( !rc && (page = page_list_remove_head(&d->page_list)) ) - { - if ( is_hvm_domain(d) || - (page->u.inuse.type_info & PGT_type_mask) == PGT_writable_page ) - { - mfn_t mfn = page_to_mfn(page); - gfn_t gfn = mfn_to_gfn(d, mfn); - unsigned int flush_flags = 0; - - if ( !gfn_eq(gfn, INVALID_GFN) ) - { - dfn_t dfn = _dfn(gfn_x(gfn)); - - ASSERT(!(gfn_x(gfn) >> DEFAULT_DOMAIN_ADDRESS_WIDTH)); - BUG_ON(SHARED_M2P(gfn_x(gfn))); - rc = iommu_map(d, dfn, mfn, PAGE_ORDER_4K, - IOMMUF_readable | IOMMUF_writable, - &flush_flags); - - /* - * We may be working behind the back of a running guest, which - * may change the type of a page at any time. We can't prevent - * this (for instance, by bumping the type count while mapping - * the page) without causing legitimate guest type-change - * operations to fail. So after adding the page to the IOMMU, - * check again to make sure this is still valid. NB that the - * writable entry in the iommu is harmless until later, when - * the actual device gets assigned. - */ - if ( !rc && !is_hvm_domain(d) && - ((page->u.inuse.type_info & PGT_type_mask) != - PGT_writable_page) ) - { - rc = iommu_unmap(d, dfn, PAGE_ORDER_4K, &flush_flags); - /* If the type changed yet again, simply force a retry. */ - if ( !rc && ((page->u.inuse.type_info & PGT_type_mask) == - PGT_writable_page) ) - rc = -ERESTART; - } - } - if ( rc ) - { - page_list_add(page, &d->page_list); - break; - } - } - page_list_add_tail(page, &d->arch.relmem_list); - if ( !(++n & 0xff) && !page_list_empty(&d->page_list) && - hypercall_preempt_check() ) - rc = -ERESTART; - } - - if ( !rc ) - { - /* - * The expectation here is that generally there are many normal pages - * on relmem_list (the ones we put there) and only few being in an - * offline/broken state. The latter ones are always at the head of the - * list. Hence we first move the whole list, and then move back the - * first few entries. - */ - page_list_move(&d->page_list, &d->arch.relmem_list); - while ( !page_list_empty(&d->page_list) && - (page = page_list_first(&d->page_list), - (page->count_info & (PGC_state|PGC_broken))) ) - { - page_list_del(page, &d->page_list); - page_list_add_tail(page, &d->arch.relmem_list); - } - } - - spin_unlock(&d->page_alloc_lock); - - if ( !rc ) - /* - * flush_flags are not tracked across hypercall pre-emption so - * assume a full flush is necessary. - */ - rc = iommu_iotlb_flush_all( - d, IOMMU_FLUSHF_added | IOMMU_FLUSHF_modified); - - if ( rc && rc != -ERESTART ) - iommu_teardown(d); - - return rc; -} - void __hwdom_init arch_iommu_check_autotranslated_hwdom(struct domain *d) { if ( !is_iommu_enabled(d) ) diff --git a/xen/include/asm-arm/iommu.h b/xen/include/asm-arm/iommu.h index 904c9aec11..1577e83d2b 100644 --- a/xen/include/asm-arm/iommu.h +++ b/xen/include/asm-arm/iommu.h @@ -21,7 +21,7 @@ struct arch_iommu }; /* Always share P2M Table between the CPU and the IOMMU */ -#define iommu_use_hap_pt(d) (has_iommu_pt(d)) +#define iommu_use_hap_pt(d) is_iommu_enabled(d) const struct iommu_ops *iommu_get_ops(void); void iommu_set_ops(const struct iommu_ops *ops); diff --git a/xen/include/asm-x86/iommu.h b/xen/include/asm-x86/iommu.h index 31fda4b0cf..5071afd6a5 100644 --- a/xen/include/asm-x86/iommu.h +++ b/xen/include/asm-x86/iommu.h @@ -88,7 +88,7 @@ extern const struct iommu_init_ops *iommu_init_ops; /* Are we using the domain P2M table as its IOMMU pagetable? */ #define iommu_use_hap_pt(d) \ - (hap_enabled(d) && has_iommu_pt(d) && iommu_hap_pt_share) + (hap_enabled(d) && is_iommu_enabled(d) && iommu_hap_pt_share) void iommu_update_ire_from_apic(unsigned int apic, unsigned int reg, unsigned int value); unsigned int iommu_read_apic_from_ire(unsigned int apic, unsigned int reg); diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index a519f4d87b..be7af49c1e 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -79,15 +79,9 @@ void iommu_domain_destroy(struct domain *d); void arch_iommu_domain_destroy(struct domain *d); int arch_iommu_domain_init(struct domain *d); -int arch_iommu_populate_page_table(struct domain *d); void arch_iommu_check_autotranslated_hwdom(struct domain *d); void arch_iommu_hwdom_init(struct domain *d); -int iommu_construct(struct domain *d); - -/* Function used internally, use iommu_domain_destroy */ -void iommu_teardown(struct domain *d); - /* * The following flags are passed to map operations and passed by lookup * operations. @@ -254,13 +248,6 @@ struct iommu_ops { # define iommu_vcall iommu_call #endif -enum iommu_status -{ - IOMMU_STATUS_disabled, - IOMMU_STATUS_initializing, - IOMMU_STATUS_initialized -}; - struct domain_iommu { struct arch_iommu arch; @@ -280,9 +267,6 @@ struct domain_iommu { /* Features supported by the IOMMU */ DECLARE_BITMAP(features, IOMMU_FEAT_count); - /* Status of guest IOMMU mappings */ - enum iommu_status status; - /* * Does the guest reqire mappings to be synchonized, to maintain * the default dfn == pfn map. (See comment on dfn at the top of diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 2d17c84915..ae1faf70d3 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -966,10 +966,8 @@ static inline bool is_hwdom_pinned_vcpu(const struct vcpu *v) } #ifdef CONFIG_HAS_PASSTHROUGH -#define has_iommu_pt(d) (dom_iommu(d)->status != IOMMU_STATUS_disabled) #define need_iommu_pt_sync(d) (dom_iommu(d)->need_sync) #else -#define has_iommu_pt(d) false #define need_iommu_pt_sync(d) false #endif From patchwork Fri Sep 13 09:47:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11144301 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BFE241599 for ; Fri, 13 Sep 2019 09:49:48 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9CE182089F for ; Fri, 13 Sep 2019 09:49:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=citrix.com header.i=@citrix.com header.b="C92VEzGD" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9CE182089F Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=citrix.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBO-0002IS-H2; Fri, 13 Sep 2019 09:48:02 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBN-0002I3-JE for xen-devel@lists.xenproject.org; Fri, 13 Sep 2019 09:48:01 +0000 X-Inumbo-ID: 8ae58254-d60b-11e9-978d-bc764e2007e4 Received: from esa3.hc3370-68.iphmx.com (unknown [216.71.145.155]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 8ae58254-d60b-11e9-978d-bc764e2007e4; Fri, 13 Sep 2019 09:47:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1568368069; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=gmGi7PDPIsspe8vTYaBFwudhgPdj5W7YGoiz7uqDdDk=; b=C92VEzGDlBBkF27jnb0fy2U7jh3cjGgJRg0dzOqbwoMKn+Kdv9sSTOMW 2pH1Be5l2j07ns9KQmt/lgbX0iB3gM7sZSd3tLXxFEjD1/FJi/5rsaQgw PvMAcCv5gAulTIVSR+dCKXTCjaRBYtbpo7BslP4IKRWPoHAzXy80qB0uy 4=; Authentication-Results: esa3.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=paul.durrant@citrix.com; spf=Pass smtp.mailfrom=Paul.Durrant@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of paul.durrant@citrix.com) identity=pra; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="paul.durrant@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa3.hc3370-68.iphmx.com: domain of Paul.Durrant@citrix.com designates 162.221.158.21 as permitted sender) identity=mailfrom; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="Paul.Durrant@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:162.221.158.21 ip4:162.221.156.83 ~all" Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: Ou/6V9ssKNHgtTUGxV4fMd61dnxpgZkwGGwlF3WRBNsccVRDh/xq1dKE+T0LlCCmTGYeHCqpzX 9SGQ/iKCOGCTpcXydj4yyIq+gos7oMu3Ajc5eM/OGOuk9yzrxlpLQjjyB0qdJ/viE8AyMVojQp VxE/SS26f91a5J/p/gvGnI7mT44YGNG2CHsGL5FQJ15aOe0q0ITpFcuyNWu8mpzIXx8BRxh/4/ GH//qrDiNOjz/17RmudqH0CGJMhO+8qQ7MW6i0ub1NlocQ0fB2iXeZ7KNUwGDTYpO5WwM/ZjvP X/I= X-SBRS: 2.7 X-MesageID: 5528291 X-Ironport-Server: esa3.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.64,500,1559534400"; d="scan'208";a="5528291" From: Paul Durrant To: Date: Fri, 13 Sep 2019 10:47:40 +0100 Message-ID: <20190913094741.31451-6-paul.durrant@citrix.com> X-Mailer: git-send-email 2.20.1.2.gb21ebb671 In-Reply-To: <20190913094741.31451-1-paul.durrant@citrix.com> References: <20190913094741.31451-1-paul.durrant@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH v10 5/6] iommu: tidy up iommu_use_hap_pt() and need_iommu_pt_sync() macros X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ian Jackson , Tim Deegan , Julien Grall , Paul Durrant , Jan Beulich , Volodymyr Babchuk , =?utf-8?q?Roger_Pau_Monn?= =?utf-8?q?=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" Thes macros really ought to live in the common xen/iommu.h header rather then being distributed amongst architecture specific iommu headers and xen/sched.h. This patch moves them there. NOTE: Disabling 'sharept' in the command line iommu options should really be hard error on ARM (as opposed to just being ignored), so define 'iommu_hap_pt_share' to be true for ARM (via ARM-selected CONFIG_IOMMU_FORCE_PT_SHARE). Signed-off-by: Paul Durrant Reviewed-by: Jan Beulich --- Cc: Andrew Cooper Cc: George Dunlap Cc: Ian Jackson Cc: Julien Grall Cc: Konrad Rzeszutek Wilk Cc: Stefano Stabellini Cc: Tim Deegan Cc: Wei Liu Cc: Volodymyr Babchuk Cc: "Roger Pau Monné" Previously part of https://lists.xenproject.org/archives/html/xen-devel/2019-07/msg02267.html v9: - Add new Kconfig option to cause 'iommu_hap_pt_share' to be defined to true, rather than using CONFIG_ARM, as requested by Julien - Assuming Jan's R-b stands since this is a mainly a cosmetic change directly requested by another maintainer v7: - Re-work the ARM handling of 'sharept' as suggested by Jan - Make sure that need_iommu_pt_sync() always evaluates its argument --- xen/arch/arm/Kconfig | 1 + xen/drivers/passthrough/Kconfig | 3 +++ xen/include/asm-arm/iommu.h | 3 --- xen/include/asm-x86/iommu.h | 4 ---- xen/include/xen/iommu.h | 15 ++++++++++++++- xen/include/xen/sched.h | 6 ------ 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index c2db2a6953..a51aa7bfa8 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -20,6 +20,7 @@ config ARM select HAS_DEVICE_TREE select HAS_PASSTHROUGH select HAS_PDX + select IOMMU_FORCE_PT_SHARE config ARCH_DEFCONFIG string diff --git a/xen/drivers/passthrough/Kconfig b/xen/drivers/passthrough/Kconfig index a3c06491be..61f944639e 100644 --- a/xen/drivers/passthrough/Kconfig +++ b/xen/drivers/passthrough/Kconfig @@ -13,3 +13,6 @@ config ARM_SMMU Say Y here if your SoC includes an IOMMU device implementing the ARM SMMU architecture. endif + +config IOMMU_FORCE_PT_SHARE + bool diff --git a/xen/include/asm-arm/iommu.h b/xen/include/asm-arm/iommu.h index 1577e83d2b..77a94b29eb 100644 --- a/xen/include/asm-arm/iommu.h +++ b/xen/include/asm-arm/iommu.h @@ -20,9 +20,6 @@ struct arch_iommu void *priv; }; -/* Always share P2M Table between the CPU and the IOMMU */ -#define iommu_use_hap_pt(d) is_iommu_enabled(d) - const struct iommu_ops *iommu_get_ops(void); void iommu_set_ops(const struct iommu_ops *ops); diff --git a/xen/include/asm-x86/iommu.h b/xen/include/asm-x86/iommu.h index 5071afd6a5..85741f7c96 100644 --- a/xen/include/asm-x86/iommu.h +++ b/xen/include/asm-x86/iommu.h @@ -86,10 +86,6 @@ struct iommu_init_ops { extern const struct iommu_init_ops *iommu_init_ops; -/* Are we using the domain P2M table as its IOMMU pagetable? */ -#define iommu_use_hap_pt(d) \ - (hap_enabled(d) && is_iommu_enabled(d) && iommu_hap_pt_share) - void iommu_update_ire_from_apic(unsigned int apic, unsigned int reg, unsigned int value); unsigned int iommu_read_apic_from_ire(unsigned int apic, unsigned int reg); int iommu_setup_hpet_msi(struct msi_desc *); diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index be7af49c1e..28522f299f 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -56,8 +56,10 @@ extern bool_t iommu_enable, iommu_enabled; extern bool_t force_iommu, iommu_verbose, iommu_igfx; extern bool_t iommu_snoop, iommu_qinval, iommu_intremap, iommu_intpost; -#ifdef CONFIG_HVM +#if defined(CONFIG_HVM) extern bool iommu_hap_pt_share; +#elif defined(CONFIG_IOMMU_FORCE_PT_SHARE) +#define iommu_hap_pt_share true #else #define iommu_hap_pt_share false #endif @@ -279,6 +281,17 @@ struct domain_iommu { #define iommu_set_feature(d, f) set_bit(f, dom_iommu(d)->features) #define iommu_clear_feature(d, f) clear_bit(f, dom_iommu(d)->features) +/* Are we using the domain P2M table as its IOMMU pagetable? */ +#define iommu_use_hap_pt(d) \ + (hap_enabled(d) && is_iommu_enabled(d) && iommu_hap_pt_share) + +/* Does the IOMMU pagetable need to be kept synchronized with the P2M */ +#ifdef CONFIG_HAS_PASSTHROUGH +#define need_iommu_pt_sync(d) (dom_iommu(d)->need_sync) +#else +#define need_iommu_pt_sync(d) ({ (void)(d); false; }) +#endif + int __must_check iommu_suspend(void); void iommu_resume(void); void iommu_crash_shutdown(void); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index ae1faf70d3..a6896221f9 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -965,12 +965,6 @@ static inline bool is_hwdom_pinned_vcpu(const struct vcpu *v) cpumask_weight(v->cpu_hard_affinity) == 1); } -#ifdef CONFIG_HAS_PASSTHROUGH -#define need_iommu_pt_sync(d) (dom_iommu(d)->need_sync) -#else -#define need_iommu_pt_sync(d) false -#endif - static inline bool is_vcpu_online(const struct vcpu *v) { return !test_bit(_VPF_down, &v->pause_flags); From patchwork Fri Sep 13 09:47:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11144305 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2514A1599 for ; Fri, 13 Sep 2019 09:50:07 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E973820717 for ; Fri, 13 Sep 2019 09:50:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=citrix.com header.i=@citrix.com header.b="FNiJ/aie" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E973820717 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=citrix.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBZ-0002O7-9L; Fri, 13 Sep 2019 09:48:13 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i8iBX-0002NY-JD for xen-devel@lists.xenproject.org; Fri, 13 Sep 2019 09:48:11 +0000 X-Inumbo-ID: 8c4cd08e-d60b-11e9-978d-bc764e2007e4 Received: from esa3.hc3370-68.iphmx.com (unknown [216.71.145.155]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 8c4cd08e-d60b-11e9-978d-bc764e2007e4; Fri, 13 Sep 2019 09:47:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1568368071; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=WbTY2mNhpkCCRnnvV6u6nazwix3yO6pKpkjQUVrmW7I=; b=FNiJ/aieaFKySprMgdLRjU/HYUbw/yJVnpz8GvXzURYxvk2bNQlv+t18 p+sP8GaVF+9cJTNPDKg/pwsuRzaKuhJj2k/+JQMB16w7zjCs2GDt0MxFI xLmIsK6ehFetznaCGD6hPy4+qeaKoNJmB5eS7nGmlaznJDJptI67ZtPzN Q=; Authentication-Results: esa3.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=paul.durrant@citrix.com; spf=Pass smtp.mailfrom=Paul.Durrant@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of paul.durrant@citrix.com) identity=pra; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="paul.durrant@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa3.hc3370-68.iphmx.com: domain of Paul.Durrant@citrix.com designates 162.221.158.21 as permitted sender) identity=mailfrom; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="Paul.Durrant@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:162.221.158.21 ip4:162.221.156.83 ~all" Received-SPF: None (esa3.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=162.221.158.21; receiver=esa3.hc3370-68.iphmx.com; envelope-from="Paul.Durrant@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: YJYGrdbVODz5Z2ud5OjnLuyX/yxhIsjztWaCJ7oWJXbO4Y2TtHtUPmRlVzC9rSEM28QigBlyrc 1dswocwioafq5SEAo6IIW3uW/fHDT5gFOpnMLvlqEjhC1jfMlRw8ZfnWb2zcxfUg4ojeNCdKrj RVLzOP/HJ9Y80Bfxu/GJi8uXVI6fzdg6bikpzj/Cp/4tbAPpKKuW362k09bti+rWUYV82EgMtO +dRMvFfDsenAC5qAEh55DyyO3Jlg06C7RR1E12ghzSzjzJrni3MslTjIp3Tb9Of1VZzgLzbN2G 404= X-SBRS: 2.7 X-MesageID: 5528294 X-Ironport-Server: esa3.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.64,500,1559534400"; d="scan'208";a="5528294" From: Paul Durrant To: Date: Fri, 13 Sep 2019 10:47:41 +0100 Message-ID: <20190913094741.31451-7-paul.durrant@citrix.com> X-Mailer: git-send-email 2.20.1.2.gb21ebb671 In-Reply-To: <20190913094741.31451-1-paul.durrant@citrix.com> References: <20190913094741.31451-1-paul.durrant@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH v10 6/6] introduce a 'passthrough' configuration option to xl.cfg... X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ian Jackson , Tim Deegan , Julien Grall , Paul Durrant , Christian Lindig , Jan Beulich , David Scott , Anthony PERARD , Volodymyr Babchuk , =?utf-8?q?Roger_Pau_Monn?= =?utf-8?q?=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" ...and hence the ability to disable IOMMU mappings, and control EPT sharing. This patch introduces a new 'libxl_passthrough' enumeration into libxl_domain_create_info. The value will be set by xl either when it parses a new 'passthrough' option in xl.cfg, or implicitly if there is passthrough hardware specified for the domain. If the value of the passthrough configuration option is 'disabled' then the XEN_DOMCTL_CDF_iommu flag will be clear in the xen_domctl_createdomain flags, thus allowing the toolstack to control whether the domain gets IOMMU mappings or not (where previously they were globally set). If the value of the passthrough configuration option is 'sync_pt' then a new 'iommu_opts' field in xen_domctl_createdomain will be set with the value XEN_DOMCTL_IOMMU_no_sharept. This will override the global default set in iommu_hap_pt_share, thus allowing the toolstack to control whether EPT sharing is used for the domain. If the value of passthrough is 'enabled' then xl will choose an appropriate default according to the type of domain and hardware support. NOTE: The 'iommu_memkb' overhead in libxl_domain_build_info will now only be set if passthrough is 'sync_pt' (or xl has chosen this mode as a default). Signed-off-by: Paul Durrant Reviewed-by: Jan Beulich Acked-by: Christian Lindig --- Cc: Ian Jackson Cc: Wei Liu Cc: Andrew Cooper Cc: George Dunlap Cc: Julien Grall Cc: Konrad Rzeszutek Wilk Cc: Stefano Stabellini Cc: Tim Deegan Cc: Anthony PERARD Cc: David Scott Cc: Volodymyr Babchuk Cc: "Roger Pau Monné" Previously part of series https://lists.xenproject.org/archives/html/xen-devel/2019-07/msg02267.html v10: - Added abi-check runes v9: - Added the passthrough='enabled' option to xl - One cosmetic change in xen - Assume Jan's R-b stands since non-cosmetic changes are only in the toolstack v7: - Added missing breaks - Added missing ocaml binding changes v6: - Remove the libxl_physinfo() call since it's usefulness is limited to x86 v5: - Expand xen_domctl_createdomain flags field and hence bump interface version - Fix spelling mistakes in context line --- docs/man/xl.cfg.5.pod.in | 56 ++++++++++ tools/libxl/libxl.h | 9 ++ tools/libxl/libxl_create.c | 9 ++ tools/libxl/libxl_types.idl | 7 ++ tools/ocaml/libs/xc/xenctrl.ml | 4 + tools/ocaml/libs/xc/xenctrl.mli | 5 + tools/ocaml/libs/xc/xenctrl_stubs.c | 17 ++- tools/xl/xl_parse.c | 158 ++++++++++++++++++---------- xen/arch/arm/domain.c | 10 +- xen/arch/x86/domain.c | 2 +- xen/common/domain.c | 7 ++ xen/common/domctl.c | 13 --- xen/drivers/passthrough/iommu.c | 13 ++- xen/include/public/domctl.h | 10 +- xen/include/xen/iommu.h | 15 +-- 15 files changed, 254 insertions(+), 81 deletions(-) diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in index c99d40307e..154d847fb9 100644 --- a/docs/man/xl.cfg.5.pod.in +++ b/docs/man/xl.cfg.5.pod.in @@ -605,6 +605,62 @@ option should only be used with a trusted device tree. Note that the partial device tree should avoid using the phandle 65000 which is reserved by the toolstack. +=item B + +Specify whether IOMMU mappings are enabled for the domain and hence whether +it will be enabled for passthrough hardware. Valid values for this option +are: + +=over 4 + +=item B + +IOMMU mappings are disabled for the domain and so hardware may not be +passed through. + +This option is the default if no passthrough hardware is specified in the +domain's configuration. + +=item B + +This option means that IOMMU mappings will be synchronized with the +domain's P2M table as follows: + +For a PV domain, all writable pages assigned to the domain are identity +mapped by MFN in the IOMMU page table. Thus a device driver running in the +domain may program passthrough hardware for DMA using MFN values +(i.e. host/machine frame numbers) looked up in its P2M. + +For an HVM domain, all non-foreign RAM pages present in its P2M will be +mapped by GFN in the IOMMU page table. Thus a device driver running in the +domain may program passthrough hardware using GFN values (i.e. guest +physical frame numbers) without any further translation. + +This option is not currently available on Arm. + +=item B + +This option is unavailable for a PV domain. For an HVM domain, this option +means that the IOMMU will be programmed to directly reference the domain's +P2M table as its page table. From the point of view of a device driver +running in the domain this is functionally equivalent to B but +places less load on the hypervisor and so should generally be selected in +preference. However, the availability of this option is hardware specific. +If B reports B containing B then +this option may be used. + +=item B + +This option enables IOMMU mappings and selects an appropriate default +operating mode. For HVM domains running on platforms where the option is +available, this is equivalent to B. Otherwise, and also for PV +domains, this options is equivalent to B. + +This option is the default if passthrough hardware is specified in the +domain's configuration. + +=back + =back =head2 Devices diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 12545130df..e4b9c539b6 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -415,6 +415,15 @@ */ #define LIBXL_HAVE_BUILDINFO_IOMMU_MEMKB 1 +/* + * LIBXL_HAVE_CREATEINFO_PASSTHROUGH indicates that + * libxl_domain_create_info has a passthrough field (which is a + * libxl_passthrough enumeration) that indicates whether device pass- + * through is enabled for the domain and, if so, whether the IOMMU and + * HAP page tables may be shared or not. + */ +#define LIBXL_HAVE_CREATEINFO_PASSTHROUGH 1 + /* * libxl ABI compatibility * diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index 59dbcb50a0..6b7702db17 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -578,6 +578,15 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config, libxl_defbool_val(info->oos) ? 0 : XEN_DOMCTL_CDF_oos_off; } + LOG(DETAIL, "passthrough: %s", + libxl_passthrough_to_string(info->passthrough)); + + if (info->passthrough != LIBXL_PASSTHROUGH_DISABLED) + create.flags |= XEN_DOMCTL_CDF_iommu; + + if (info->passthrough == LIBXL_PASSTHROUGH_SYNC_PT) + create.iommu_opts |= XEN_DOMCTL_IOMMU_no_sharept; + /* Ultimately, handle is an array of 16 uint8_t, same as uuid */ libxl_uuid_copy(ctx, (libxl_uuid *)&create.handle, &info->uuid); diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index d52c63b6b0..22f05711e3 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -263,6 +263,12 @@ libxl_vkb_backend = Enumeration("vkb_backend", [ (2, "LINUX") ]) +libxl_passthrough = Enumeration("passthrough", [ + (0, "disabled"), + (1, "sync_pt"), + (2, "share_pt"), + ]) + # # Complex libxl types # @@ -408,6 +414,7 @@ libxl_domain_create_info = Struct("domain_create_info",[ ("pool_name", string), ("run_hotplug_scripts",libxl_defbool), ("driver_domain",libxl_defbool), + ("passthrough", libxl_passthrough), ], dir=DIR_IN) libxl_domain_restore_params = Struct("domain_restore_params", [ diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml index de4bae6012..e00a74d48d 100644 --- a/tools/ocaml/libs/xc/xenctrl.ml +++ b/tools/ocaml/libs/xc/xenctrl.ml @@ -65,11 +65,15 @@ type domain_create_flag = | CDF_XS_DOMAIN | CDF_IOMMU +type domain_create_iommu_opts = + | IOMMU_NO_SHAREPT + type domctl_create_config = { ssidref: int32; handle: string; flags: domain_create_flag list; + iommu_opts: domain_create_iommu_opts list; max_vcpus: int; max_evtchn_port: int; max_grant_frames: int; diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli index c885e75895..0e7049d708 100644 --- a/tools/ocaml/libs/xc/xenctrl.mli +++ b/tools/ocaml/libs/xc/xenctrl.mli @@ -57,10 +57,15 @@ type domain_create_flag = | CDF_OOS_OFF | CDF_XS_DOMAIN | CDF_IOMMU + +type domain_create_iommu_opts = + | IOMMU_NO_SHAREPT + type domctl_create_config = { ssidref: int32; handle: string; flags: domain_create_flag list; + iommu_opts: domain_create_iommu_opts list; max_vcpus: int; max_evtchn_port: int; max_grant_frames: int; diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c index 0cdd873599..cf860fe45e 100644 --- a/tools/ocaml/libs/xc/xenctrl_stubs.c +++ b/tools/ocaml/libs/xc/xenctrl_stubs.c @@ -190,11 +190,12 @@ CAMLprim value stub_xc_domain_create(value xch, value config) #define VAL_SSIDREF Field(config, 0) #define VAL_HANDLE Field(config, 1) #define VAL_FLAGS Field(config, 2) -#define VAL_MAX_VCPUS Field(config, 3) -#define VAL_MAX_EVTCHN_PORT Field(config, 4) -#define VAL_MAX_GRANT_FRAMES Field(config, 5) -#define VAL_MAX_MAPTRACK_FRAMES Field(config, 6) -#define VAL_ARCH Field(config, 7) +#define VAL_IOMMU_OPTS Field(config, 3) +#define VAL_MAX_VCPUS Field(config, 4) +#define VAL_MAX_EVTCHN_PORT Field(config, 5) +#define VAL_MAX_GRANT_FRAMES Field(config, 6) +#define VAL_MAX_MAPTRACK_FRAMES Field(config, 7) +#define VAL_ARCH Field(config, 8) uint32_t domid = 0; int result; @@ -213,6 +214,11 @@ CAMLprim value stub_xc_domain_create(value xch, value config) /* ! XEN_DOMCTL_CDF_ XEN_DOMCTL_CDF_MAX max */ (VAL_FLAGS); + cfg.iommu_opts = ocaml_list_to_c_bitmap + /* ! domain_create_iommu_opts IOMMU_ none */ + /* ! XEN_DOMCTL_IOMMU_ XEN_DOMCTL_IOMMU_MAX max */ + (VAL_IOMMU_OPTS); + arch_domconfig = Field(VAL_ARCH, 0); switch ( Tag_val(VAL_ARCH) ) { @@ -247,6 +253,7 @@ CAMLprim value stub_xc_domain_create(value xch, value config) #undef VAL_MAX_GRANT_FRAMES #undef VAL_MAX_EVTCHN_PORT #undef VAL_MAX_VCPUS +#undef VAL_IOMMU_OPTS #undef VAL_FLAGS #undef VAL_HANDLE #undef VAL_SSIDREF diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c index 293f5f730e..4b2baa0403 100644 --- a/tools/xl/xl_parse.c +++ b/tools/xl/xl_parse.c @@ -1461,6 +1461,107 @@ void parse_config_data(const char *config_source, exit(1); } + if (!xlu_cfg_get_list (config, "pci", &pcis, 0, 0)) { + d_config->num_pcidevs = 0; + d_config->pcidevs = NULL; + for(i = 0; (buf = xlu_cfg_get_listitem (pcis, i)) != NULL; i++) { + libxl_device_pci *pcidev; + + pcidev = ARRAY_EXTEND_INIT_NODEVID(d_config->pcidevs, + d_config->num_pcidevs, + libxl_device_pci_init); + pcidev->msitranslate = pci_msitranslate; + pcidev->power_mgmt = pci_power_mgmt; + pcidev->permissive = pci_permissive; + pcidev->seize = pci_seize; + /* + * Like other pci option, the per-device policy always follows + * the global policy by default. + */ + pcidev->rdm_policy = b_info->u.hvm.rdm.policy; + e = xlu_pci_parse_bdf(config, pcidev, buf); + if (e) { + fprintf(stderr, + "unable to parse PCI BDF `%s' for passthrough\n", + buf); + exit(-e); + } + } + if (d_config->num_pcidevs && c_info->type == LIBXL_DOMAIN_TYPE_PV) + libxl_defbool_set(&b_info->u.pv.e820_host, true); + } + + if (!xlu_cfg_get_list (config, "dtdev", &dtdevs, 0, 0)) { + d_config->num_dtdevs = 0; + d_config->dtdevs = NULL; + for (i = 0; (buf = xlu_cfg_get_listitem(dtdevs, i)) != NULL; i++) { + libxl_device_dtdev *dtdev; + + dtdev = ARRAY_EXTEND_INIT_NODEVID(d_config->dtdevs, + d_config->num_dtdevs, + libxl_device_dtdev_init); + + dtdev->path = strdup(buf); + if (dtdev->path == NULL) { + fprintf(stderr, "unable to duplicate string for dtdevs\n"); + exit(-1); + } + } + } + + if (xlu_cfg_get_string(config, "passthrough", &buf, 0)) { + buf = (d_config->num_pcidevs || d_config->num_dtdevs) + ? "enabled" : "disabled"; + } + + if (!strncmp(buf, "enabled", strlen(buf))) { + /* Choose a suitable default */ + c_info->passthrough = + (c_info->type == LIBXL_DOMAIN_TYPE_PV) || !iommu_hap_pt_share + ? LIBXL_PASSTHROUGH_SYNC_PT : LIBXL_PASSTHROUGH_SHARE_PT; + } else { + libxl_passthrough o; + + e = libxl_passthrough_from_string(buf, &o); + if (e) { + fprintf(stderr, + "ERROR: unknown passthrough option '%s'\n", + buf); + exit(-ERROR_FAIL); + } + + switch (o) { + case LIBXL_PASSTHROUGH_DISABLED: + if (d_config->num_pcidevs || d_config->num_dtdevs) { + fprintf(stderr, + "ERROR: passthrough disabled but devices are specified\n"); + exit(-ERROR_FAIL); + } + break; + case LIBXL_PASSTHROUGH_SHARE_PT: + if (c_info->type == LIBXL_DOMAIN_TYPE_PV) { + fprintf(stderr, + "ERROR: passthrough=\"share_pt\" not valid for PV domain\n"); + exit(-ERROR_FAIL); + } else if (!iommu_hap_pt_share) { + fprintf(stderr, + "ERROR: passthrough=\"share_pt\" not supported on this platform\n"); + exit(-ERROR_FAIL); + } + break; + case LIBXL_PASSTHROUGH_SYNC_PT: + break; + } + + c_info->passthrough = o; + } + + if ((c_info->passthrough != LIBXL_PASSTHROUGH_DISABLED) && !iommu_enabled) { + fprintf(stderr, + "ERROR: passthrough not supported on this platform\n"); + exit(-ERROR_FAIL); + } + /* libxl_get_required_shadow_memory() and * libxl_get_required_iommu_memory() must be called after final values * (default or specified) for vcpus and memory are set, because the @@ -1470,11 +1571,10 @@ void parse_config_data(const char *config_source, : libxl_get_required_shadow_memory(b_info->max_memkb, b_info->max_vcpus); - /* No IOMMU reservation is needed if either the IOMMU is disabled or it - * can share the P2M. */ - b_info->iommu_memkb = (!iommu_enabled || iommu_hap_pt_share) - ? 0 - : libxl_get_required_iommu_memory(b_info->max_memkb); + /* No IOMMU reservation is needed if passthrough mode is not 'sync_pt' */ + b_info->iommu_memkb = (c_info->passthrough == LIBXL_PASSTHROUGH_SYNC_PT) + ? libxl_get_required_iommu_memory(b_info->max_memkb) + : 0; xlu_cfg_get_defbool(config, "nomigrate", &b_info->disable_migrate, 0); @@ -2298,54 +2398,6 @@ skip_vfb: } } - if (!xlu_cfg_get_list (config, "pci", &pcis, 0, 0)) { - d_config->num_pcidevs = 0; - d_config->pcidevs = NULL; - for(i = 0; (buf = xlu_cfg_get_listitem (pcis, i)) != NULL; i++) { - libxl_device_pci *pcidev; - - pcidev = ARRAY_EXTEND_INIT_NODEVID(d_config->pcidevs, - d_config->num_pcidevs, - libxl_device_pci_init); - pcidev->msitranslate = pci_msitranslate; - pcidev->power_mgmt = pci_power_mgmt; - pcidev->permissive = pci_permissive; - pcidev->seize = pci_seize; - /* - * Like other pci option, the per-device policy always follows - * the global policy by default. - */ - pcidev->rdm_policy = b_info->u.hvm.rdm.policy; - e = xlu_pci_parse_bdf(config, pcidev, buf); - if (e) { - fprintf(stderr, - "unable to parse PCI BDF `%s' for passthrough\n", - buf); - exit(-e); - } - } - if (d_config->num_pcidevs && c_info->type == LIBXL_DOMAIN_TYPE_PV) - libxl_defbool_set(&b_info->u.pv.e820_host, true); - } - - if (!xlu_cfg_get_list (config, "dtdev", &dtdevs, 0, 0)) { - d_config->num_dtdevs = 0; - d_config->dtdevs = NULL; - for (i = 0; (buf = xlu_cfg_get_listitem(dtdevs, i)) != NULL; i++) { - libxl_device_dtdev *dtdev; - - dtdev = ARRAY_EXTEND_INIT_NODEVID(d_config->dtdevs, - d_config->num_dtdevs, - libxl_device_dtdev_init); - - dtdev->path = strdup(buf); - if (dtdev->path == NULL) { - fprintf(stderr, "unable to duplicate string for dtdevs\n"); - exit(-1); - } - } - } - if (!xlu_cfg_get_list(config, "usbctrl", &usbctrls, 0, 0)) { d_config->num_usbctrls = 0; d_config->usbctrls = NULL; diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index ae13e47e86..61d35cd120 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -617,6 +617,14 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config) return -EINVAL; } + /* The P2M table must always be shared between the CPU and the IOMMU */ + if ( config->iommu_opts & XEN_DOMCTL_IOMMU_no_sharept ) + { + dprintk(XENLOG_INFO, + "Unsupported iommu option: XEN_DOMCTL_IOMMU_no_sharept\n"); + return -EINVAL; + } + /* Fill in the native GIC version, passed back to the toolstack. */ if ( config->arch.gic_version == XEN_DOMCTL_CONFIG_GIC_NATIVE ) { @@ -677,7 +685,7 @@ int arch_domain_create(struct domain *d, ASSERT(config != NULL); /* p2m_init relies on some value initialized by the IOMMU subsystem */ - if ( (rc = iommu_domain_init(d)) != 0 ) + if ( (rc = iommu_domain_init(d, config->iommu_opts)) != 0 ) goto fail; if ( (rc = p2m_init(d)) != 0 ) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 4b0ad5e15d..fb8b397be2 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -611,7 +611,7 @@ int arch_domain_create(struct domain *d, if ( (rc = init_domain_irq_mapping(d)) != 0 ) goto fail; - if ( (rc = iommu_domain_init(d)) != 0 ) + if ( (rc = iommu_domain_init(d, config->iommu_opts)) != 0 ) goto fail; psr_domain_init(d); diff --git a/xen/common/domain.c b/xen/common/domain.c index 4681f29c8b..0733ee8b0a 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -308,6 +308,13 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config) return -EINVAL; } + if ( !(config->flags & XEN_DOMCTL_CDF_iommu) && config->iommu_opts ) + { + dprintk(XENLOG_INFO, + "IOMMU options specified but IOMMU not enabled\n"); + return -EINVAL; + } + if ( config->max_vcpus < 1 ) { dprintk(XENLOG_INFO, "No vCPUS\n"); diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 5dcfe3c8f6..6e6e9b9866 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -515,19 +515,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) rover = dom; } - /* - * For now, make sure the createdomain IOMMU flag is set if the - * IOMMU is enabled. When the flag comes under toolstack control - * this can go away. - */ - if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_iommu ) - { - ASSERT_UNREACHABLE(); - return -EINVAL; - } - if ( iommu_enabled ) - op->u.createdomain.flags |= XEN_DOMCTL_CDF_iommu; - d = domain_create(dom, &op->u.createdomain, false); if ( IS_ERR(d) ) { diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index a49346394d..4171c3cf6f 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -168,7 +168,7 @@ static void __hwdom_init check_hwdom_reqs(struct domain *d) iommu_hwdom_strict = true; } -int iommu_domain_init(struct domain *d) +int iommu_domain_init(struct domain *d, unsigned int opts) { struct domain_iommu *hd = dom_iommu(d); int ret = 0; @@ -192,6 +192,15 @@ int iommu_domain_init(struct domain *d) if ( is_hardware_domain(d) ) check_hwdom_reqs(d); /* may modify iommu_hwdom_strict */ + /* + * Use shared page tables for HAP and IOMMU if the global option + * is enabled (from which we can infer the h/w is capable) and + * the domain options do not disallow it. HAP must, of course, also + * be enabled. + */ + hd->hap_pt_share = hap_enabled(d) && iommu_hap_pt_share && + !(opts & XEN_DOMCTL_IOMMU_no_sharept); + /* * NB: 'relaxed' h/w domains don't need the IOMMU mappings to be kept * in-sync with their assigned pages because all host RAM will be @@ -200,6 +209,8 @@ int iommu_domain_init(struct domain *d) if ( !is_hardware_domain(d) || iommu_hwdom_strict ) hd->need_sync = !iommu_use_hap_pt(d); + ASSERT(!(hd->need_sync && hd->hap_pt_share)); + return 0; } diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 1b3176adb5..ba84aea6ab 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -38,7 +38,7 @@ #include "hvm/save.h" #include "memory.h" -#define XEN_DOMCTL_INTERFACE_VERSION 0x00000011 +#define XEN_DOMCTL_INTERFACE_VERSION 0x00000012 /* * NB. xen_domctl.domain is an IN/OUT parameter for this operation. @@ -73,6 +73,14 @@ struct xen_domctl_createdomain { uint32_t flags; +#define _XEN_DOMCTL_IOMMU_no_sharept 0 +#define XEN_DOMCTL_IOMMU_no_sharept (1U << _XEN_DOMCTL_IOMMU_no_sharept) + +/* Max XEN_DOMCTL_IOMMU_* constant. Used for ABI checking. */ +#define XEN_DOMCTL_IOMMU_MAX XEN_DOMCTL_IOMMU_no_sharept + + uint32_t iommu_opts; + /* * Various domain limits, which impact the quantity of resources (global * mapping space, xenheap, etc) a guest may consume. diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index 28522f299f..aae9283d1c 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -75,7 +75,7 @@ extern unsigned int iommu_dev_iotlb_timeout; int iommu_setup(void); int iommu_hardware_setup(void); -int iommu_domain_init(struct domain *d); +int iommu_domain_init(struct domain *d, unsigned int opts); void iommu_hwdom_init(struct domain *d); void iommu_domain_destroy(struct domain *d); @@ -269,10 +269,14 @@ struct domain_iommu { /* Features supported by the IOMMU */ DECLARE_BITMAP(features, IOMMU_FEAT_count); + /* Does the guest share HAP mapping with the IOMMU? */ + bool hap_pt_share; + /* - * Does the guest reqire mappings to be synchonized, to maintain - * the default dfn == pfn map. (See comment on dfn at the top of - * include/xen/mm.h). + * Does the guest require mappings to be synchronized, to maintain + * the default dfn == pfn map? (See comment on dfn at the top of + * include/xen/mm.h). Note that hap_pt_share == false does not + * necessarily imply this is true. */ bool need_sync; }; @@ -282,8 +286,7 @@ struct domain_iommu { #define iommu_clear_feature(d, f) clear_bit(f, dom_iommu(d)->features) /* Are we using the domain P2M table as its IOMMU pagetable? */ -#define iommu_use_hap_pt(d) \ - (hap_enabled(d) && is_iommu_enabled(d) && iommu_hap_pt_share) +#define iommu_use_hap_pt(d) (dom_iommu(d)->hap_pt_share) /* Does the IOMMU pagetable need to be kept synchronized with the P2M */ #ifdef CONFIG_HAS_PASSTHROUGH