From patchwork Tue Mar 2 20:38:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446009 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcJ72Jp6z9sWd for ; Tue, 2 Mar 2021 23:43:51 +1100 (AEDT) Received: from localhost ([::1]:43476 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4NR-0002Kt-9D for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:43:49 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:60796) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4JN-00075o-PT for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:37 -0500 Received: from mga09.intel.com ([134.134.136.24]:30211) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4JK-0002c1-83 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:37 -0500 IronPort-SDR: AewFfih2rBjdrOM1XSEry+O2KgeqA7dr1Kw639BGbtT2Cg8NILwedH6QAMs0evq7+Bq+qjWD7s Gv28Z2CNGxsA== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="186914641" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="186914641" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:39:32 -0800 IronPort-SDR: Nb0nayM7mT+7J4D9VH8hW0lS5n3V8W5f+0jxAEqWRE/izBvONNtONP5LsNGN46cc7Tr021AGao pdpqHpBxu5cA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472668" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:39:27 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 01/25] scripts/update-linux-headers: Import iommu.h Date: Wed, 3 Mar 2021 04:38:03 +0800 Message-Id: <20210302203827.437645-2-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.24; envelope-from=yi.l.liu@intel.com; helo=mga09.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, Cornelia Huck , eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Eric Auger Update the script to import the new iommu.h uapi header. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Michael S. Tsirkin Cc: Cornelia Huck Cc: Paolo Bonzini Acked-by: Cornelia Huck Signed-off-by: Eric Auger Signed-off-by: Liu Yi L --- scripts/update-linux-headers.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index fa6f2b6272..f588678837 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -142,7 +142,7 @@ done rm -rf "$output/linux-headers/linux" mkdir -p "$output/linux-headers/linux" -for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h \ +for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h iommu.h \ psci.h psp-sev.h userfaultfd.h mman.h; do cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux" done From patchwork Tue Mar 2 20:38:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446016 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcNF2X6Jz9sS8 for ; Tue, 2 Mar 2021 23:47:25 +1100 (AEDT) Received: from localhost ([::1]:51850 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4Qt-00064A-9l for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:47:23 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:60818) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4JP-00076b-90 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:39 -0500 Received: from mga09.intel.com ([134.134.136.24]:30217) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4JN-0002cX-GF for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:38 -0500 IronPort-SDR: FTaEhU2ER6K+cmJUildgZm8wxs6iobENsOeHWWS21BIpwwU/ObYNoTLcDUueWviRONdczwfFRQ K8b4tCiRXu9w== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="186914653" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="186914653" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:39:36 -0800 IronPort-SDR: r/ewTO+5AFOUkHg1yaEaZlfm+WpYcvQcwKp+niRcUnM95I7/SF0R9H0Zp9F0GvrvT5p0KPAZ8U lZWu7p2i+kDQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472686" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:39:32 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 02/25] scripts/update-linux-headers: Import ioasid.h Date: Wed, 3 Mar 2021 04:38:04 +0800 Message-Id: <20210302203827.437645-3-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.24; envelope-from=yi.l.liu@intel.com; helo=mga09.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, Cornelia Huck , eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Update the script to import the new ioasid.h uapi header. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Michael S. Tsirkin Cc: Cornelia Huck Cc: Paolo Bonzini Signed-off-by: Liu Yi L --- scripts/update-linux-headers.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index f588678837..7fbd8ace69 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -142,7 +142,7 @@ done rm -rf "$output/linux-headers/linux" mkdir -p "$output/linux-headers/linux" -for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h iommu.h \ +for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h iommu.h ioasid.h \ psci.h psp-sev.h userfaultfd.h mman.h; do cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux" done From patchwork Tue Mar 2 20:38:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446006 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcDy4n9hz9sWd for ; Tue, 2 Mar 2021 23:41:06 +1100 (AEDT) Received: from localhost ([::1]:35468 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4Km-0007CB-7P for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:41:04 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:60858) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4JW-0007BE-Qu for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:47 -0500 Received: from mga09.intel.com ([134.134.136.24]:30217) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4JR-0002cX-OP for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:46 -0500 IronPort-SDR: ogTbOhvy+8NHa0hYJV6HK4tTfw8PxABnIf403xqkyJ+x2swoX3+mxqIw0TAPvK4G2etrQTbTIE wqb9lNMX5i2A== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="186914663" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="186914663" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:39:41 -0800 IronPort-SDR: esX9dabqUCU8wQHcaUZc7LSandQ/1jiAANvdyf/JCeKBeibdHtgr1YuzG5sne3F3YFoI61C/t3 1MAgfwwf76TA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472702" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:39:36 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 03/25] header file update VFIO/IOMMU vSVA APIs kernel 5.12-rc1 Date: Wed, 3 Mar 2021 04:38:05 +0800 Message-Id: <20210302203827.437645-4-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.24; envelope-from=yi.l.liu@intel.com; helo=mga09.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Update the kernel uapi/linux/iommu.h, vfio.h and ioasid.h. This commit updates kernel headers from the below branch: https://github.com/jacobpan/linux.git vsva-linux-5.12-rc1-v8 Note: this should be replaced with a full header files update when the vSVA uPAPI is stable. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Michael S. Tsirkin Signed-off-by: Liu Yi L --- linux-headers/linux/iommu.h | 413 ++++++++++++++++++++++++++++++++++++ linux-headers/linux/vfio.h | 84 ++++++++ 2 files changed, 497 insertions(+) create mode 100644 linux-headers/linux/iommu.h diff --git a/linux-headers/linux/iommu.h b/linux-headers/linux/iommu.h new file mode 100644 index 0000000000..8824029e53 --- /dev/null +++ b/linux-headers/linux/iommu.h @@ -0,0 +1,413 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * IOMMU user API definitions + */ + +#ifndef _IOMMU_H +#define _IOMMU_H + +#include + +#define IOMMU_FAULT_PERM_READ (1 << 0) /* read */ +#define IOMMU_FAULT_PERM_WRITE (1 << 1) /* write */ +#define IOMMU_FAULT_PERM_EXEC (1 << 2) /* exec */ +#define IOMMU_FAULT_PERM_PRIV (1 << 3) /* privileged */ + +/* Generic fault types, can be expanded IRQ remapping fault */ +enum iommu_fault_type { + IOMMU_FAULT_DMA_UNRECOV = 1, /* unrecoverable fault */ + IOMMU_FAULT_PAGE_REQ, /* page request fault */ +}; + +enum iommu_fault_reason { + IOMMU_FAULT_REASON_UNKNOWN = 0, + + /* Could not access the PASID table (fetch caused external abort) */ + IOMMU_FAULT_REASON_PASID_FETCH, + + /* PASID entry is invalid or has configuration errors */ + IOMMU_FAULT_REASON_BAD_PASID_ENTRY, + + /* + * PASID is out of range (e.g. exceeds the maximum PASID + * supported by the IOMMU) or disabled. + */ + IOMMU_FAULT_REASON_PASID_INVALID, + + /* + * An external abort occurred fetching (or updating) a translation + * table descriptor + */ + IOMMU_FAULT_REASON_WALK_EABT, + + /* + * Could not access the page table entry (Bad address), + * actual translation fault + */ + IOMMU_FAULT_REASON_PTE_FETCH, + + /* Protection flag check failed */ + IOMMU_FAULT_REASON_PERMISSION, + + /* access flag check failed */ + IOMMU_FAULT_REASON_ACCESS, + + /* Output address of a translation stage caused Address Size fault */ + IOMMU_FAULT_REASON_OOR_ADDRESS, +}; + +/** + * struct iommu_fault_unrecoverable - Unrecoverable fault data + * @reason: reason of the fault, from &enum iommu_fault_reason + * @flags: parameters of this fault (IOMMU_FAULT_UNRECOV_* values) + * @pasid: Process Address Space ID + * @perm: requested permission access using by the incoming transaction + * (IOMMU_FAULT_PERM_* values) + * @addr: offending page address + * @fetch_addr: address that caused a fetch abort, if any + */ +struct iommu_fault_unrecoverable { + __u32 reason; +#define IOMMU_FAULT_UNRECOV_PASID_VALID (1 << 0) +#define IOMMU_FAULT_UNRECOV_ADDR_VALID (1 << 1) +#define IOMMU_FAULT_UNRECOV_FETCH_ADDR_VALID (1 << 2) + __u32 flags; + __u32 pasid; + __u32 perm; + __u64 addr; + __u64 fetch_addr; +}; + +/** + * struct iommu_fault_page_request - Page Request data + * @flags: encodes whether the corresponding fields are valid and whether this + * is the last page in group (IOMMU_FAULT_PAGE_REQUEST_* values). + * When IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID is set, the page response + * must have the same PASID value as the page request. When it is clear, + * the page response should not have a PASID. + * @pasid: Process Address Space ID + * @grpid: Page Request Group Index + * @perm: requested page permissions (IOMMU_FAULT_PERM_* values) + * @addr: page address + * @private_data: device-specific private information + */ +struct iommu_fault_page_request { +#define IOMMU_FAULT_PAGE_REQUEST_PASID_VALID (1 << 0) +#define IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE (1 << 1) +#define IOMMU_FAULT_PAGE_REQUEST_PRIV_DATA (1 << 2) +#define IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID (1 << 3) + __u32 flags; + __u32 pasid; + __u32 grpid; + __u32 perm; + __u64 addr; + __u64 private_data[2]; +}; + +/** + * struct iommu_fault - Generic fault data + * @type: fault type from &enum iommu_fault_type + * @padding: reserved for future use (should be zero) + * @event: fault event, when @type is %IOMMU_FAULT_DMA_UNRECOV + * @prm: Page Request message, when @type is %IOMMU_FAULT_PAGE_REQ + * @padding2: sets the fault size to allow for future extensions + */ +struct iommu_fault { + __u32 type; + __u32 padding; + union { + struct iommu_fault_unrecoverable event; + struct iommu_fault_page_request prm; + __u8 padding2[56]; + }; +}; + +/** + * enum iommu_page_response_code - Return status of fault handlers + * @IOMMU_PAGE_RESP_SUCCESS: Fault has been handled and the page tables + * populated, retry the access. This is "Success" in PCI PRI. + * @IOMMU_PAGE_RESP_FAILURE: General error. Drop all subsequent faults from + * this device if possible. This is "Response Failure" in PCI PRI. + * @IOMMU_PAGE_RESP_INVALID: Could not handle this fault, don't retry the + * access. This is "Invalid Request" in PCI PRI. + */ +enum iommu_page_response_code { + IOMMU_PAGE_RESP_SUCCESS = 0, + IOMMU_PAGE_RESP_INVALID, + IOMMU_PAGE_RESP_FAILURE, +}; + +/** + * struct iommu_page_response - Generic page response information + * @argsz: User filled size of this data + * @version: API version of this structure + * @flags: encodes whether the corresponding fields are valid + * (IOMMU_FAULT_PAGE_RESPONSE_* values) + * @pasid: Process Address Space ID + * @grpid: Page Request Group Index + * @code: response code from &enum iommu_page_response_code + */ +struct iommu_page_response { + __u32 argsz; +#define IOMMU_PAGE_RESP_VERSION_1 1 + __u32 version; +#define IOMMU_PAGE_RESP_PASID_VALID (1 << 0) + __u32 flags; + __u32 pasid; + __u32 grpid; + __u32 code; +}; + +/* defines the granularity of the invalidation */ +enum iommu_inv_granularity { + IOMMU_INV_GRANU_DOMAIN, /* domain-selective invalidation */ + IOMMU_INV_GRANU_PASID, /* PASID-selective invalidation */ + IOMMU_INV_GRANU_ADDR, /* page-selective invalidation */ + IOMMU_INV_GRANU_NR, /* number of invalidation granularities */ +}; + +/** + * struct iommu_inv_addr_info - Address Selective Invalidation Structure + * + * @flags: indicates the granularity of the address-selective invalidation + * - If the PASID bit is set, the @pasid field is populated and the invalidation + * relates to cache entries tagged with this PASID and matching the address + * range. + * - If ARCHID bit is set, @archid is populated and the invalidation relates + * to cache entries tagged with this architecture specific ID and matching + * the address range. + * - Both PASID and ARCHID can be set as they may tag different caches. + * - If neither PASID or ARCHID is set, global addr invalidation applies. + * - The LEAF flag indicates whether only the leaf PTE caching needs to be + * invalidated and other paging structure caches can be preserved. + * @pasid: process address space ID + * @archid: architecture-specific ID + * @addr: first stage/level input address + * @granule_size: page/block size of the mapping in bytes + * @nb_granules: number of contiguous granules to be invalidated + */ +struct iommu_inv_addr_info { +#define IOMMU_INV_ADDR_FLAGS_PASID (1 << 0) +#define IOMMU_INV_ADDR_FLAGS_ARCHID (1 << 1) +#define IOMMU_INV_ADDR_FLAGS_LEAF (1 << 2) + __u32 flags; + __u32 archid; + __u64 pasid; + __u64 addr; + __u64 granule_size; + __u64 nb_granules; +}; + +/** + * struct iommu_inv_pasid_info - PASID Selective Invalidation Structure + * + * @flags: indicates the granularity of the PASID-selective invalidation + * - If the PASID bit is set, the @pasid field is populated and the invalidation + * relates to cache entries tagged with this PASID and matching the address + * range. + * - If the ARCHID bit is set, the @archid is populated and the invalidation + * relates to cache entries tagged with this architecture specific ID and + * matching the address range. + * - Both PASID and ARCHID can be set as they may tag different caches. + * - At least one of PASID or ARCHID must be set. + * @pasid: process address space ID + * @archid: architecture-specific ID + */ +struct iommu_inv_pasid_info { +#define IOMMU_INV_PASID_FLAGS_PASID (1 << 0) +#define IOMMU_INV_PASID_FLAGS_ARCHID (1 << 1) + __u32 flags; + __u32 archid; + __u64 pasid; +}; + +/** + * struct iommu_cache_invalidate_info - First level/stage invalidation + * information + * @argsz: User filled size of this data + * @version: API version of this structure + * @cache: bitfield that allows to select which caches to invalidate + * @granularity: defines the lowest granularity used for the invalidation: + * domain > PASID > addr + * @padding: reserved for future use (should be zero) + * @pasid_info: invalidation data when @granularity is %IOMMU_INV_GRANU_PASID + * @addr_info: invalidation data when @granularity is %IOMMU_INV_GRANU_ADDR + * + * Not all the combinations of cache/granularity are valid: + * + * +--------------+---------------+---------------+---------------+ + * | type / | DEV_IOTLB | IOTLB | PASID | + * | granularity | | | cache | + * +==============+===============+===============+===============+ + * | DOMAIN | N/A | Y | Y | + * +--------------+---------------+---------------+---------------+ + * | PASID | Y | Y | Y | + * +--------------+---------------+---------------+---------------+ + * | ADDR | Y | Y | N/A | + * +--------------+---------------+---------------+---------------+ + * + * Invalidations by %IOMMU_INV_GRANU_DOMAIN don't take any argument other than + * @version and @cache. + * + * If multiple cache types are invalidated simultaneously, they all + * must support the used granularity. + */ +struct iommu_cache_invalidate_info { + __u32 argsz; +#define IOMMU_CACHE_INVALIDATE_INFO_VERSION_1 1 + __u32 version; +/* IOMMU paging structure cache */ +#define IOMMU_CACHE_INV_TYPE_IOTLB (1 << 0) /* IOMMU IOTLB */ +#define IOMMU_CACHE_INV_TYPE_DEV_IOTLB (1 << 1) /* Device IOTLB */ +#define IOMMU_CACHE_INV_TYPE_PASID (1 << 2) /* PASID cache */ +#define IOMMU_CACHE_INV_TYPE_NR (3) + __u8 cache; + __u8 granularity; + __u8 padding[6]; + union { + struct iommu_inv_pasid_info pasid_info; + struct iommu_inv_addr_info addr_info; + } granu; +}; + +/** + * struct iommu_gpasid_bind_data_vtd - Intel VT-d specific data on device and guest + * SVA binding. + * + * @flags: VT-d PASID table entry attributes + * @pat: Page attribute table data to compute effective memory type + * @emt: Extended memory type + * + * Only guest vIOMMU selectable and effective options are passed down to + * the host IOMMU. + */ +struct iommu_gpasid_bind_data_vtd { +#define IOMMU_SVA_VTD_GPASID_SRE (1 << 0) /* supervisor request */ +#define IOMMU_SVA_VTD_GPASID_EAFE (1 << 1) /* extended access enable */ +#define IOMMU_SVA_VTD_GPASID_PCD (1 << 2) /* page-level cache disable */ +#define IOMMU_SVA_VTD_GPASID_PWT (1 << 3) /* page-level write through */ +#define IOMMU_SVA_VTD_GPASID_EMTE (1 << 4) /* extended mem type enable */ +#define IOMMU_SVA_VTD_GPASID_CD (1 << 5) /* PASID-level cache disable */ +#define IOMMU_SVA_VTD_GPASID_LAST (1 << 6) + __u64 flags; + __u32 pat; + __u32 emt; +}; + +#define IOMMU_SVA_VTD_GPASID_MTS_MASK (IOMMU_SVA_VTD_GPASID_CD | \ + IOMMU_SVA_VTD_GPASID_EMTE | \ + IOMMU_SVA_VTD_GPASID_PCD | \ + IOMMU_SVA_VTD_GPASID_PWT) + +/** + * struct iommu_gpasid_bind_data - Information about device and guest PASID binding + * @argsz: User filled size of this data + * @version: Version of this data structure + * @format: PASID table entry format + * @flags: Additional information on guest bind request + * @gpgd: Guest page directory base of the guest mm to bind + * @hpasid: Process address space ID used for the guest mm in host IOMMU + * @gpasid: Process address space ID used for the guest mm in guest IOMMU + * @addr_width: Guest virtual address width + * @padding: Reserved for future use (should be zero) + * @vtd: Intel VT-d specific data + * + * Guest to host PASID mapping can be an identity or non-identity, where guest + * has its own PASID space. For non-identify mapping, guest to host PASID lookup + * is needed when VM programs guest PASID into an assigned device. VMM may + * trap such PASID programming then request host IOMMU driver to convert guest + * PASID to host PASID based on this bind data. + */ +struct iommu_gpasid_bind_data { + __u32 argsz; +#define IOMMU_GPASID_BIND_VERSION_1 1 + __u32 version; +#define IOMMU_PASID_FORMAT_INTEL_VTD 1 +#define IOMMU_PASID_FORMAT_LAST 2 + __u32 format; + __u32 addr_width; +#define IOMMU_SVA_GPASID_VAL (1 << 0) /* guest PASID valid */ + __u64 flags; + __u64 gpgd; + __u64 hpasid; + __u64 gpasid; + __u8 padding[8]; + /* Vendor specific data */ + union { + struct iommu_gpasid_bind_data_vtd vtd; + } vendor; +}; + +/* + * struct iommu_nesting_info_vtd - Intel VT-d specific nesting info. + * + * @flags: VT-d specific flags. Currently reserved for future + * extension. must be set to 0. + * @cap_reg: Describe basic capabilities as defined in VT-d capability + * register. + * @ecap_reg: Describe the extended capabilities as defined in VT-d + * extended capability register. + */ +struct iommu_nesting_info_vtd { + __u32 flags; + __u8 padding[12]; + __u64 cap_reg; + __u64 ecap_reg; +}; + +/* + * struct iommu_nesting_info - Information for nesting-capable IOMMU. + * userspace should check it before using + * nesting capability. + * + * @argsz: size of the whole structure. + * @flags: currently reserved for future extension. must set to 0. + * @format: PASID table entry format, the same definition as struct + * iommu_gpasid_bind_data @format. + * @features: supported nesting features. + * @addr_width: the output addr width of first level/stage translation + * @pasid_bits: maximum supported PASID bits, 0 represents no PASID + * support. + * @vendor: vendor specific data, structure type can be deduced from + * @format field. + * + * +===============+======================================================+ + * | feature | Notes | + * +===============+======================================================+ + * | BIND_PGTBL | IOMMU vendor driver sets it to mandate userspace to | + * | | bind the first level/stage page table to associated | + * | | PASID (either the one specified in bind request or | + * | | the default PASID of iommu domain), through IOMMU | + * | | UAPI. | + * +---------------+------------------------------------------------------+ + * | CACHE_INVLD | IOMMU vendor driver sets it to mandate userspace to | + * | | explicitly invalidate the IOMMU cache through IOMMU | + * | | UAPI according to vendor-specific requirement when | + * | | changing the 1st level/stage page table. | + * +---------------+------------------------------------------------------+ + * + * data struct types defined for @format: + * +================================+=====================================+ + * | @format | data struct | + * +================================+=====================================+ + * | IOMMU_PASID_FORMAT_INTEL_VTD | struct iommu_nesting_info_vtd | + * +--------------------------------+-------------------------------------+ + * + */ +struct iommu_nesting_info { + __u32 argsz; + __u32 flags; + __u32 format; +#define IOMMU_NESTING_FEAT_BIND_PGTBL (1 << 0) +#define IOMMU_NESTING_FEAT_CACHE_INVLD (1 << 1) + __u32 features; + __u16 addr_width; + __u16 pasid_bits; + __u8 padding[12]; + /* Vendor specific data */ + union { + struct iommu_nesting_info_vtd vtd; + } vendor; +}; + +#endif /* _IOMMU_H */ diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index 609099e455..59fbf7f109 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -14,6 +14,7 @@ #include #include +#include #define VFIO_API_VERSION 0 @@ -46,6 +47,12 @@ */ #define VFIO_NOIOMMU_IOMMU 8 +/* Supports VFIO_DMA_UNMAP_FLAG_ALL */ +#define VFIO_UNMAP_ALL 9 + +/* Supports the vaddr flag for DMA map and unmap */ +#define VFIO_UPDATE_VADDR 10 + /* * The IOCTL interface is designed for extensibility by embedding the * structure length (argsz) and flags into structures passed between @@ -1067,6 +1074,24 @@ struct vfio_iommu_type1_info_dma_avail { __u32 avail; }; +/* + * The nesting capability allows to report the related capability + * and info for nesting iommu type. + * + * The structures below define version 1 of this capability. + * + * Nested capabilities should be checked by the userspace after + * setting VFIO_TYPE1_NESTING_IOMMU. + * + * @info: the nesting info provided by IOMMU driver. + */ +#define VFIO_IOMMU_TYPE1_INFO_CAP_NESTING 4 + +struct vfio_iommu_type1_info_cap_nesting { + struct vfio_info_cap_header header; + struct iommu_nesting_info info; +}; + #define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12) /** @@ -1074,12 +1099,22 @@ struct vfio_iommu_type1_info_dma_avail { * * Map process virtual addresses to IO virtual addresses using the * provided struct vfio_dma_map. Caller sets argsz. READ &/ WRITE required. + * + * If flags & VFIO_DMA_MAP_FLAG_VADDR, update the base vaddr for iova, and + * unblock translation of host virtual addresses in the iova range. The vaddr + * must have previously been invalidated with VFIO_DMA_UNMAP_FLAG_VADDR. To + * maintain memory consistency within the user application, the updated vaddr + * must address the same memory object as originally mapped. Failure to do so + * will result in user memory corruption and/or device misbehavior. iova and + * size must match those in the original MAP_DMA call. Protection is not + * changed, and the READ & WRITE flags must be 0. */ struct vfio_iommu_type1_dma_map { __u32 argsz; __u32 flags; #define VFIO_DMA_MAP_FLAG_READ (1 << 0) /* readable from device */ #define VFIO_DMA_MAP_FLAG_WRITE (1 << 1) /* writable from device */ +#define VFIO_DMA_MAP_FLAG_VADDR (1 << 2) __u64 vaddr; /* Process virtual address */ __u64 iova; /* IO virtual address */ __u64 size; /* Size of mapping (bytes) */ @@ -1102,6 +1137,7 @@ struct vfio_bitmap { * field. No guarantee is made to the user that arbitrary unmaps of iova * or size different from those used in the original mapping call will * succeed. + * * VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP should be set to get the dirty bitmap * before unmapping IO virtual addresses. When this flag is set, the user must * provide a struct vfio_bitmap in data[]. User must provide zero-allocated @@ -1111,11 +1147,21 @@ struct vfio_bitmap { * indicates that the page at that offset from iova is dirty. A Bitmap of the * pages in the range of unmapped size is returned in the user-provided * vfio_bitmap.data. + * + * If flags & VFIO_DMA_UNMAP_FLAG_ALL, unmap all addresses. iova and size + * must be 0. This cannot be combined with the get-dirty-bitmap flag. + * + * If flags & VFIO_DMA_UNMAP_FLAG_VADDR, do not unmap, but invalidate host + * virtual addresses in the iova range. Tasks that attempt to translate an + * iova's vaddr will block. DMA to already-mapped pages continues. This + * cannot be combined with the get-dirty-bitmap flag. */ struct vfio_iommu_type1_dma_unmap { __u32 argsz; __u32 flags; #define VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP (1 << 0) +#define VFIO_DMA_UNMAP_FLAG_ALL (1 << 1) +#define VFIO_DMA_UNMAP_FLAG_VADDR (1 << 2) __u64 iova; /* IO virtual address */ __u64 size; /* Size of mapping (bytes) */ __u8 data[]; @@ -1181,6 +1227,44 @@ struct vfio_iommu_type1_dirty_bitmap_get { #define VFIO_IOMMU_DIRTY_PAGES _IO(VFIO_TYPE, VFIO_BASE + 17) +/** + * VFIO_IOMMU_NESTING_OP - _IOW(VFIO_TYPE, VFIO_BASE + 18, + * struct vfio_iommu_type1_nesting_op) + * + * This interface allows userspace to utilize the nesting IOMMU + * capabilities as reported in VFIO_IOMMU_TYPE1_INFO_CAP_NESTING + * cap through VFIO_IOMMU_GET_INFO. For platforms which require + * system wide PASID, PASID will be allocated by VFIO_IOMMU_PASID + * _REQUEST. + * + * @data[] types defined for each op: + * +=================+===============================================+ + * | NESTING OP | @data[] | + * +=================+===============================================+ + * | BIND_PGTBL | struct iommu_gpasid_bind_data | + * +-----------------+-----------------------------------------------+ + * | UNBIND_PGTBL | struct iommu_gpasid_bind_data | + * +-----------------+-----------------------------------------------+ + * | CACHE_INVLD | struct iommu_cache_invalidate_info | + * +-----------------+-----------------------------------------------+ + * + * returns: 0 on success, -errno on failure. + */ +struct vfio_iommu_type1_nesting_op { + __u32 argsz; + __u32 flags; +#define VFIO_NESTING_OP_MASK (0xffff) /* lower 16-bits for op */ + __u8 data[]; +}; + +enum { + VFIO_IOMMU_NESTING_OP_BIND_PGTBL, + VFIO_IOMMU_NESTING_OP_UNBIND_PGTBL, + VFIO_IOMMU_NESTING_OP_CACHE_INVLD, +}; + +#define VFIO_IOMMU_NESTING_OP _IO(VFIO_TYPE, VFIO_BASE + 18) + /* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */ /* From patchwork Tue Mar 2 20:38:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446017 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcNn5Jr7z9sVt for ; Tue, 2 Mar 2021 23:47:53 +1100 (AEDT) Received: from localhost ([::1]:53246 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4RF-0006dU-0w for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:47:47 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:60896) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Jb-0007GH-J2 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:52 -0500 Received: from mga09.intel.com ([134.134.136.24]:30220) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4JW-0002eE-SD for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:51 -0500 IronPort-SDR: RFsjR989biCOiRxgaktkgJ8kna2FT08WxtO2GcJAQ4An7wkTeVeO9Dd1y1noOWFg04KYyI2b0R 2rfzbv3Xmmcg== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="186914670" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="186914670" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:39:45 -0800 IronPort-SDR: uuHVWbr3jJZ/CcV5GM0GzfXjKPko6QRsJanFi5dQ4OVzoqQjmlVX16USgWbHhy2C0mJcKrf5T2 mTScQiHqC/bg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472712" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:39:41 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 04/25] hw/pci: modify pci_setup_iommu() to set PCIIOMMUOps Date: Wed, 3 Mar 2021 04:38:06 +0800 Message-Id: <20210302203827.437645-5-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.24; envelope-from=yi.l.liu@intel.com; helo=mga09.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch modifies pci_setup_iommu() to set PCIIOMMUOps instead of setting PCIIOMMUFunc. PCIIOMMUFunc is used to get an address space for a PCI device in vendor specific way. The PCIIOMMUOps still offers this functionality. But using PCIIOMMUOps leaves space to add more iommu related vendor specific operations. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Michael S. Tsirkin Reviewed-by: David Gibson Reviewed-by: Peter Xu Signed-off-by: Liu Yi L --- rfcv9 -> rfcv10: *) Fix a bug in pci_device_iommu_address_space() + iommu_bus->iommu_ops->get_address_space) && => + !iommu_bus->iommu_ops->get_address_space) && --- hw/alpha/typhoon.c | 6 +++++- hw/arm/smmu-common.c | 6 +++++- hw/hppa/dino.c | 6 +++++- hw/i386/amd_iommu.c | 6 +++++- hw/i386/intel_iommu.c | 6 +++++- hw/pci-host/designware.c | 6 +++++- hw/pci-host/pnv_phb3.c | 6 +++++- hw/pci-host/pnv_phb4.c | 6 +++++- hw/pci-host/ppce500.c | 6 +++++- hw/pci-host/prep.c | 6 +++++- hw/pci-host/sabre.c | 6 +++++- hw/pci/pci.c | 18 +++++++++++++----- hw/ppc/ppc440_pcix.c | 6 +++++- hw/ppc/spapr_pci.c | 6 +++++- hw/s390x/s390-pci-bus.c | 8 ++++++-- hw/virtio/virtio-iommu.c | 6 +++++- include/hw/pci/pci.h | 8 ++++++-- include/hw/pci/pci_bus.h | 2 +- 18 files changed, 96 insertions(+), 24 deletions(-) diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index a42b319812..47ff561c81 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -740,6 +740,10 @@ static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &s->pchip.iommu_as; } +static const PCIIOMMUOps typhoon_iommu_ops = { + .get_address_space = typhoon_pci_dma_iommu, +}; + static void typhoon_set_irq(void *opaque, int irq, int level) { TyphoonState *s = opaque; @@ -897,7 +901,7 @@ PCIBus *typhoon_init(MemoryRegion *ram, ISABus **isa_bus, qemu_irq *p_rtc_irq, "iommu-typhoon", UINT64_MAX); address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu), "pchip0-pci"); - pci_setup_iommu(b, typhoon_pci_dma_iommu, s); + pci_setup_iommu(b, &typhoon_iommu_ops, s); /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops, diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 405d5c5325..bbaf6565cf 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -444,6 +444,10 @@ static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) return &sdev->as; } +static const PCIIOMMUOps smmu_ops = { + .get_address_space = smmu_find_add_as, +}; + IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid) { uint8_t bus_n, devfn; @@ -514,7 +518,7 @@ static void smmu_base_realize(DeviceState *dev, Error **errp) s->smmu_pcibus_by_busptr = g_hash_table_new(NULL, NULL); if (s->primary_bus) { - pci_setup_iommu(s->primary_bus, smmu_find_add_as, s); + pci_setup_iommu(s->primary_bus, &smmu_ops, s); } else { error_setg(errp, "SMMU is not attached to any PCI bus!"); } diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 5b82c9440d..1b2228891a 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -459,6 +459,10 @@ static AddressSpace *dino_pcihost_set_iommu(PCIBus *bus, void *opaque, return &s->bm_as; } +static const PCIIOMMUOps dino_iommu_ops = { + .get_address_space = dino_pcihost_set_iommu, +}; + /* * Dino interrupts are connected as shown on Page 78, Table 23 * (Little-endian bit numbers) @@ -580,7 +584,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, memory_region_add_subregion(&s->bm, 0xfff00000, &s->bm_cpu_alias); address_space_init(&s->bm_as, &s->bm, "pci-bm"); - pci_setup_iommu(b, dino_pcihost_set_iommu, s); + pci_setup_iommu(b, &dino_iommu_ops, s); *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0); *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0); diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 74a93a5d93..3676a20c25 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1452,6 +1452,10 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &iommu_as[devfn]->as; } +static const PCIIOMMUOps amdvi_iommu_ops = { + .get_address_space = amdvi_host_dma_iommu, +}; + static const MemoryRegionOps mmio_mem_ops = { .read = amdvi_mmio_read, .write = amdvi_mmio_write, @@ -1579,7 +1583,7 @@ static void amdvi_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, AMDVI_BASE_ADDR); - pci_setup_iommu(bus, amdvi_host_dma_iommu, s); + pci_setup_iommu(bus, &amdvi_iommu_ops, s); s->devid = object_property_get_int(OBJECT(&s->pci), "addr", &error_abort); msi_init(&s->pci.dev, 0, 1, true, false, errp); amdvi_init(s); diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index ccaf322681..dd11248b6b 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3756,6 +3756,10 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &vtd_as->as; } +static PCIIOMMUOps vtd_iommu_ops = { + .get_address_space = vtd_host_dma_iommu, +}; + static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) { X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); @@ -3867,7 +3871,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) g_free, g_free); vtd_init(s); sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, Q35_HOST_BRIDGE_IOMMU_ADDR); - pci_setup_iommu(bus, vtd_host_dma_iommu, dev); + pci_setup_iommu(bus, &vtd_iommu_ops, dev); /* Pseudo address space under root PCI bus. */ x86ms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC); qemu_add_machine_init_done_notifier(&vtd_machine_done_notify); diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index bde3a343a2..f289e77667 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -664,6 +664,10 @@ static AddressSpace *designware_pcie_host_set_iommu(PCIBus *bus, void *opaque, return &s->pci.address_space; } +static const PCIIOMMUOps designware_iommu_ops = { + .get_address_space = designware_pcie_host_set_iommu, +}; + static void designware_pcie_host_realize(DeviceState *dev, Error **errp) { PCIHostState *pci = PCI_HOST_BRIDGE(dev); @@ -705,7 +709,7 @@ static void designware_pcie_host_realize(DeviceState *dev, Error **errp) address_space_init(&s->pci.address_space, &s->pci.address_space_root, "pcie-bus-address-space"); - pci_setup_iommu(pci->bus, designware_pcie_host_set_iommu, s); + pci_setup_iommu(pci->bus, &designware_iommu_ops, s); qdev_realize(DEVICE(&s->root), BUS(pci->bus), &error_fatal); } diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index a7f9685005..bcfad7d16f 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -962,6 +962,10 @@ static AddressSpace *pnv_phb3_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &ds->dma_as; } +static PCIIOMMUOps pnv_phb3_iommu_ops = { + .get_address_space = pnv_phb3_dma_iommu, +}; + static void pnv_phb3_instance_init(Object *obj) { PnvPHB3 *phb = PNV_PHB3(obj); @@ -1049,7 +1053,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) &phb->pci_mmio, &phb->pci_io, 0, 4, TYPE_PNV_PHB3_ROOT_BUS); - pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb); + pci_setup_iommu(pci->bus, &pnv_phb3_iommu_ops, phb); /* Add a single Root port */ qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id); diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 54f57c660a..1b10bf6a2b 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1150,6 +1150,10 @@ static AddressSpace *pnv_phb4_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &ds->dma_as; } +static PCIIOMMUOps pnv_phb4_iommu_ops = { + .get_address_space = pnv_phb4_dma_iommu, +}; + static void pnv_phb4_instance_init(Object *obj) { PnvPHB4 *phb = PNV_PHB4(obj); @@ -1204,7 +1208,7 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) pnv_phb4_set_irq, pnv_phb4_map_irq, phb, &phb->pci_mmio, &phb->pci_io, 0, 4, TYPE_PNV_PHB4_ROOT_BUS); - pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb); + pci_setup_iommu(pci->bus, &pnv_phb4_iommu_ops, phb); /* Add a single Root port */ qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id); diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 5ad1424b31..fad5583ee6 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -436,6 +436,10 @@ static AddressSpace *e500_pcihost_set_iommu(PCIBus *bus, void *opaque, return &s->bm_as; } +static const PCIIOMMUOps ppce500_iommu_ops = { + .get_address_space = e500_pcihost_set_iommu, +}; + static void e500_pcihost_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); @@ -470,7 +474,7 @@ static void e500_pcihost_realize(DeviceState *dev, Error **errp) memory_region_init(&s->bm, OBJECT(s), "bm-e500", UINT64_MAX); memory_region_add_subregion(&s->bm, 0x0, &s->busmem); address_space_init(&s->bm_as, &s->bm, "pci-bm"); - pci_setup_iommu(b, e500_pcihost_set_iommu, s); + pci_setup_iommu(b, &ppce500_iommu_ops, s); pci_create_simple(b, 0, "e500-host-bridge"); diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index 0a9162fba9..a03fc8a583 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -223,6 +223,10 @@ static AddressSpace *raven_pcihost_set_iommu(PCIBus *bus, void *opaque, return &s->bm_as; } +static const PCIIOMMUOps raven_iommu_ops = { + .get_address_space = raven_pcihost_set_iommu, +}; + static void raven_change_gpio(void *opaque, int n, int level) { PREPPCIState *s = opaque; @@ -311,7 +315,7 @@ static void raven_pcihost_initfn(Object *obj) memory_region_add_subregion(&s->bm, 0 , &s->bm_pci_memory_alias); memory_region_add_subregion(&s->bm, 0x80000000, &s->bm_ram_alias); address_space_init(&s->bm_as, &s->bm, "raven-bm"); - pci_setup_iommu(&s->pci_bus, raven_pcihost_set_iommu, s); + pci_setup_iommu(&s->pci_bus, &raven_iommu_ops, s); h->bus = &s->pci_bus; diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c index f41a0cc301..342b861e52 100644 --- a/hw/pci-host/sabre.c +++ b/hw/pci-host/sabre.c @@ -113,6 +113,10 @@ static AddressSpace *sabre_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &is->iommu_as; } +static const PCIIOMMUOps sabre_iommu_ops = { + .get_address_space = sabre_pci_dma_iommu, +}; + static void sabre_config_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { @@ -385,7 +389,7 @@ static void sabre_realize(DeviceState *dev, Error **errp) /* IOMMU */ memory_region_add_subregion_overlap(&s->sabre_config, 0x200, sysbus_mmio_get_region(SYS_BUS_DEVICE(s->iommu), 0), 1); - pci_setup_iommu(phb->bus, sabre_pci_dma_iommu, s->iommu); + pci_setup_iommu(phb->bus, &sabre_iommu_ops, s->iommu); /* APB secondary busses */ pci_dev = pci_new_multifunction(PCI_DEVFN(1, 0), true, diff --git a/hw/pci/pci.c b/hw/pci/pci.c index fa97a671d1..61f115d742 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2671,7 +2671,13 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) PCIBus *iommu_bus = bus; uint8_t devfn = dev->devfn; - while (iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) { + /* + * get_address_space() callback is mandatory, so needs to ensure its + * presence in the iommu_bus search. + */ + while (iommu_bus && (!iommu_bus->iommu_ops || + !iommu_bus->iommu_ops->get_address_space) && + iommu_bus->parent_dev) { PCIBus *parent_bus = pci_get_bus(iommu_bus->parent_dev); /* @@ -2710,15 +2716,17 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) iommu_bus = parent_bus; } - if (iommu_bus && iommu_bus->iommu_fn) { - return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, devfn); + if (iommu_bus && iommu_bus->iommu_ops && + iommu_bus->iommu_ops->get_address_space) { + return iommu_bus->iommu_ops->get_address_space(bus, + iommu_bus->iommu_opaque, devfn); } return &address_space_memory; } -void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque) +void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque) { - bus->iommu_fn = fn; + bus->iommu_ops = ops; bus->iommu_opaque = opaque; } diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c index 91cbcd0504..679f6781f0 100644 --- a/hw/ppc/ppc440_pcix.c +++ b/hw/ppc/ppc440_pcix.c @@ -449,6 +449,10 @@ static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn) return &s->bm_as; } +static const PCIIOMMUOps ppc440_iommu_ops = { + .get_address_space = ppc440_pcix_set_iommu, +}; + /* * Some guests on sam460ex write all kinds of garbage here such as * missing enable bit and low bits set and still expect this to work @@ -501,7 +505,7 @@ static void ppc440_pcix_realize(DeviceState *dev, Error **errp) memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX); memory_region_add_subregion(&s->bm, 0x0, &s->busmem); address_space_init(&s->bm_as, &s->bm, "pci-bm"); - pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s); + pci_setup_iommu(h->bus, &ppc440_iommu_ops, s); memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE); memory_region_init_io(&h->conf_mem, OBJECT(s), &ppc440_pcix_host_conf_ops, diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index f1c7479816..4276ef5d29 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -782,6 +782,10 @@ static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &phb->iommu_as; } +static const PCIIOMMUOps spapr_iommu_ops = { + .get_address_space = spapr_pci_dma_iommu, +}; + static char *spapr_phb_vfio_get_loc_code(SpaprPhbState *sphb, PCIDevice *pdev) { char *path = NULL, *buf = NULL, *host = NULL; @@ -1989,7 +1993,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&sphb->iommu_root, SPAPR_PCI_MSI_WINDOW, &sphb->msiwindow); - pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb); + pci_setup_iommu(bus, &spapr_iommu_ops, sphb); pci_bus_set_route_irq_fn(bus, spapr_route_intx_pin_to_irq); diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index dd138dae94..4a6b41be26 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -636,6 +636,10 @@ static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &iommu->as; } +static const PCIIOMMUOps s390_iommu_ops = { + .get_address_space = s390_pci_dma_iommu, +}; + static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) { uint8_t expected, actual; @@ -808,7 +812,7 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp) b = pci_register_root_bus(dev, NULL, s390_pci_set_irq, s390_pci_map_irq, NULL, get_system_memory(), get_system_io(), 0, 64, TYPE_PCI_BUS); - pci_setup_iommu(b, s390_pci_dma_iommu, s); + pci_setup_iommu(b, &s390_iommu_ops, s); bus = BUS(b); qbus_set_hotplug_handler(bus, OBJECT(dev)); @@ -983,7 +987,7 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, pdev = PCI_DEVICE(dev); pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq); - pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s); + pci_setup_iommu(&pb->sec_bus, &s390_iommu_ops, s); qbus_set_hotplug_handler(BUS(&pb->sec_bus), OBJECT(s)); diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index c2883a2f6c..9a83ad00e9 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -315,6 +315,10 @@ static AddressSpace *virtio_iommu_find_add_as(PCIBus *bus, void *opaque, return &sdev->as; } +static const PCIIOMMUOps virtio_iommu_ops = { + .get_address_space = virtio_iommu_find_add_as, +}; + static int virtio_iommu_attach(VirtIOIOMMU *s, struct virtio_iommu_req_attach *req) { @@ -989,7 +993,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) s->as_by_busptr = g_hash_table_new_full(NULL, NULL, NULL, g_free); if (s->primary_bus) { - pci_setup_iommu(s->primary_bus, virtio_iommu_find_add_as, s); + pci_setup_iommu(s->primary_bus, &virtio_iommu_ops, s); } else { error_setg(errp, "VIRTIO-IOMMU is not attached to any PCI bus!"); } diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 1bc231480f..d6b962f646 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -485,10 +485,14 @@ void pci_bus_get_w64_range(PCIBus *bus, Range *range); void pci_device_deassert_intx(PCIDevice *dev); -typedef AddressSpace *(*PCIIOMMUFunc)(PCIBus *, void *, int); +typedef struct PCIIOMMUOps PCIIOMMUOps; +struct PCIIOMMUOps { + AddressSpace * (*get_address_space)(PCIBus *bus, + void *opaque, int32_t devfn); +}; AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); -void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque); +void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *iommu_ops, void *opaque); static inline void pci_set_byte(uint8_t *config, uint8_t val) diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h index 347440d42c..b56f313c04 100644 --- a/include/hw/pci/pci_bus.h +++ b/include/hw/pci/pci_bus.h @@ -29,7 +29,7 @@ enum PCIBusFlags { struct PCIBus { BusState qbus; enum PCIBusFlags flags; - PCIIOMMUFunc iommu_fn; + const PCIIOMMUOps *iommu_ops; void *iommu_opaque; uint8_t devfn_min; uint32_t slot_reserved_mask; From patchwork Tue Mar 2 20:38:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446007 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcFY1c4Pz9sVt for ; Tue, 2 Mar 2021 23:41:37 +1100 (AEDT) Received: from localhost ([::1]:36894 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4LH-0007r3-3t for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:41:35 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:60908) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Jd-0007H6-1w for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:53 -0500 Received: from mga09.intel.com ([134.134.136.24]:30217) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Ja-0002cX-FQ for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:39:52 -0500 IronPort-SDR: +M2b2G4R81+aIfyacrHvPFtCOgPk0lUMO6B03zuQ8hMp4U5VsVkCpz86AhLNleDJOmtIuLr2NH eCEgLHCcnPSA== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="186914677" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="186914677" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:39:49 -0800 IronPort-SDR: kM17WPcU1rDLUcKBqP29NCQv69tGvu1ojdMAzsCbJIX9/DWxCpfNETG1swiSkDjtXA4gXh9IMa uy8qvj6rEm9w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472720" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:39:45 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 05/25] hw/pci: introduce pci_device_get_iommu_attr() Date: Wed, 3 Mar 2021 04:38:07 +0800 Message-Id: <20210302203827.437645-6-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.24; envelope-from=yi.l.liu@intel.com; helo=mga09.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds pci_device_get_iommu_attr() to get vIOMMU attributes. e.g. if nesting IOMMU wanted. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Michael S. Tsirkin Signed-off-by: Liu Yi L --- hw/pci/pci.c | 35 ++++++++++++++++++++++++++++++----- include/hw/pci/pci.h | 7 +++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 61f115d742..19365e2799 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2665,7 +2665,8 @@ static void pci_device_class_base_init(ObjectClass *klass, void *data) } } -AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) +static void pci_device_get_iommu_bus_devfn(PCIDevice *dev, + PCIBus **pbus, uint8_t *pdevfn) { PCIBus *bus = pci_get_bus(dev); PCIBus *iommu_bus = bus; @@ -2716,14 +2717,38 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) iommu_bus = parent_bus; } - if (iommu_bus && iommu_bus->iommu_ops && - iommu_bus->iommu_ops->get_address_space) { - return iommu_bus->iommu_ops->get_address_space(bus, - iommu_bus->iommu_opaque, devfn); + *pbus = iommu_bus; + *pdevfn = devfn; +} + +AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) +{ + PCIBus *bus; + uint8_t devfn; + + pci_device_get_iommu_bus_devfn(dev, &bus, &devfn); + if (bus && bus->iommu_ops && + bus->iommu_ops->get_address_space) { + return bus->iommu_ops->get_address_space(bus, + bus->iommu_opaque, devfn); } return &address_space_memory; } +int pci_device_get_iommu_attr(PCIDevice *dev, IOMMUAttr attr, void *data) +{ + PCIBus *bus; + uint8_t devfn; + + pci_device_get_iommu_bus_devfn(dev, &bus, &devfn); + if (bus && bus->iommu_ops && + bus->iommu_ops->get_iommu_attr) { + return bus->iommu_ops->get_iommu_attr(bus, bus->iommu_opaque, + devfn, attr, data); + } + return -ENOENT; +} + void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque) { bus->iommu_ops = ops; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index d6b962f646..b99e05c81e 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -485,13 +485,20 @@ void pci_bus_get_w64_range(PCIBus *bus, Range *range); void pci_device_deassert_intx(PCIDevice *dev); +typedef enum IOMMUAttr { + IOMMU_WANT_NESTING, +} IOMMUAttr; + typedef struct PCIIOMMUOps PCIIOMMUOps; struct PCIIOMMUOps { AddressSpace * (*get_address_space)(PCIBus *bus, void *opaque, int32_t devfn); + int (*get_iommu_attr)(PCIBus *bus, void *opaque, int32_t devfn, + IOMMUAttr attr, void *data); }; AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); +int pci_device_get_iommu_attr(PCIDevice *dev, IOMMUAttr attr, void *data); void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *iommu_ops, void *opaque); static inline void From patchwork Tue Mar 2 20:38:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446008 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcFZ4dr0z9sS8 for ; Tue, 2 Mar 2021 23:41:38 +1100 (AEDT) Received: from localhost ([::1]:37084 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4LI-0007vN-Ig for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:41:36 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:60972) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Jk-0007KP-HG for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:01 -0500 Received: from mga09.intel.com ([134.134.136.24]:30230) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Jf-0002gL-QP for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:00 -0500 IronPort-SDR: 6WcUqk7U1TGuzxwjvUu2J4TCsSuYRqtOFKwgSxx0xhnU4i9k2St4iqIfEj95i73XGT1skY6FAC I2HDik+u7j6Q== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="186914690" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="186914690" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:39:54 -0800 IronPort-SDR: 7FTvWOJkC8bPt30nBvexOxahXLmfFnZEm9hZcL04uKbYV83qoJTsfdV7ZZvgE4kntC/dZHZNmF nKAVOEi9m6SA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472732" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:39:49 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 06/25] intel_iommu: add get_iommu_attr() callback Date: Wed, 3 Mar 2021 04:38:08 +0800 Message-Id: <20210302203827.437645-7-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.24; envelope-from=yi.l.liu@intel.com; helo=mga09.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Return vIOMMU attribute to caller. e.g. VFIO call via PCI layer. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Liu Yi L --- hw/i386/intel_iommu.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index dd11248b6b..d89d6d7dd5 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3462,6 +3462,28 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) return vtd_dev_as; } +static int vtd_dev_get_iommu_attr(PCIBus *bus, void *opaque, int32_t devfn, + IOMMUAttr attr, void *data) +{ + int ret = 0; + + assert(0 <= devfn && devfn < PCI_DEVFN_MAX); + + switch (attr) { + case IOMMU_WANT_NESTING: + { + bool *pdata = data; + + /* return false until vSVA is ready */ + *pdata = false; + break; + } + default: + ret = -ENOENT; + } + return ret; +} + static uint64_t get_naturally_aligned_size(uint64_t start, uint64_t size, int gaw) { @@ -3758,6 +3780,7 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) static PCIIOMMUOps vtd_iommu_ops = { .get_address_space = vtd_host_dma_iommu, + .get_iommu_attr = vtd_dev_get_iommu_attr, }; static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) From patchwork Tue Mar 2 20:38:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446021 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcS71m6Lz9sVt for ; Tue, 2 Mar 2021 23:50:46 +1100 (AEDT) Received: from localhost ([::1]:33338 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4U7-0001jo-Tz for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:50:43 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:60990) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Jn-0007Mw-Dn for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:03 -0500 Received: from mga09.intel.com ([134.134.136.24]:30234) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Jk-0002gk-8e for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:03 -0500 IronPort-SDR: fZ/Kl4VZe4x8EOPB6QKfNoy2CJi3znu3tEfDq1EI8BaDNcWSPBVpZL1NPL+wL9b0m8NGgfhv79 Fify7OFE+WZw== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="186914703" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="186914703" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:39:58 -0800 IronPort-SDR: QxOfBtNesXg2GdUovxlHAc9hXsrF6WtjSx3c+FbAonpEB7AZxBiZeH4mb5QcXTPRl7B82EKx3+ LRl8eMnKfqJA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472756" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:39:54 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 07/25] vfio: pass nesting requirement into vfio_get_group() Date: Wed, 3 Mar 2021 04:38:09 +0800 Message-Id: <20210302203827.437645-8-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.24; envelope-from=yi.l.liu@intel.com; helo=mga09.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch passes the nesting requirement into vfio_get_group() to indicate whether VFIO_TYPE1_NESTING_IOMMU is required. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Alex Williamson Signed-off-by: Liu Yi L --- hw/vfio/ap.c | 2 +- hw/vfio/ccw.c | 2 +- hw/vfio/common.c | 3 ++- hw/vfio/pci.c | 9 ++++++++- hw/vfio/platform.c | 2 +- include/hw/vfio/vfio-common.h | 3 ++- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index 9571c2f91f..06cefac7a1 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -83,7 +83,7 @@ static VFIOGroup *vfio_ap_get_group(VFIOAPDevice *vapdev, Error **errp) g_free(group_path); - return vfio_get_group(groupid, &address_space_memory, errp); + return vfio_get_group(groupid, &address_space_memory, false, errp); } static void vfio_ap_realize(DeviceState *dev, Error **errp) diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index bc78a0ad76..4a9ca9414a 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -647,7 +647,7 @@ static VFIOGroup *vfio_ccw_get_group(S390CCWDevice *cdev, Error **errp) return NULL; } - return vfio_get_group(groupid, &address_space_memory, errp); + return vfio_get_group(groupid, &address_space_memory, false, errp); } static void vfio_ccw_realize(DeviceState *dev, Error **errp) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 6ff1daa763..44097875e2 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1923,7 +1923,8 @@ static void vfio_disconnect_container(VFIOGroup *group) } } -VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp) +VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, + bool want_nested, Error **errp) { VFIOGroup *group; char path[32]; diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index f74be78209..437f51338e 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2771,6 +2771,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) int groupid; int i, ret; bool is_mdev; + bool want_nested; if (!vdev->vbasedev.sysfsdev) { if (!(~vdev->host.domain || ~vdev->host.bus || @@ -2817,7 +2818,13 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) trace_vfio_realize(vdev->vbasedev.name, groupid); - group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev), errp); + if (pci_device_get_iommu_attr(pdev, + IOMMU_WANT_NESTING, &want_nested)) { + want_nested = false; + } + + group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev), + want_nested, errp); if (!group) { goto error; } diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index cc3f66f7e4..42c6ae7689 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -577,7 +577,7 @@ static int vfio_base_device_init(VFIODevice *vbasedev, Error **errp) trace_vfio_platform_base_device_init(vbasedev->name, groupid); - group = vfio_get_group(groupid, &address_space_memory, errp); + group = vfio_get_group(groupid, &address_space_memory, false, errp); if (!group) { return -ENOENT; } diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 6141162d7a..293d3785f3 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -196,7 +196,8 @@ void vfio_region_unmap(VFIORegion *region); void vfio_region_exit(VFIORegion *region); void vfio_region_finalize(VFIORegion *region); void vfio_reset_handler(void *opaque); -VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp); +VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, + bool want_nested, Error **errp); void vfio_put_group(VFIOGroup *group); int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vbasedev, Error **errp); From patchwork Tue Mar 2 20:38:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446020 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcRK3FYtz9sS8 for ; Tue, 2 Mar 2021 23:50:05 +1100 (AEDT) Received: from localhost ([::1]:59846 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4TT-0000zq-EQ for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:50:03 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:32776) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Js-0007Os-EI for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:08 -0500 Received: from mga09.intel.com ([134.134.136.24]:30230) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Jn-0002gL-Rv for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:08 -0500 IronPort-SDR: ekAjfepFIi1YbY3ghw3qBn3B73M3iEwkA8iLYY0tpjujBeU1QlTi0C7RYKJ0CTmnARAhuEdmGj GFjrKKgMpKdg== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="186914717" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="186914717" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:02 -0800 IronPort-SDR: btrSUPgz3QbnkqBUOPX3XoGo5aHkL2h6PRi3dnBG61ML97vw0TKrOl2VsgxP/4N5JD+NLK0JZR td9lz4hvFNuQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472795" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:39:58 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 08/25] vfio: check VFIO_TYPE1_NESTING_IOMMU support Date: Wed, 3 Mar 2021 04:38:10 +0800 Message-Id: <20210302203827.437645-9-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=134.134.136.24; envelope-from=yi.l.liu@intel.com; helo=mga09.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" VFIO needs to check VFIO_TYPE1_NESTING_IOMMU support with Kernel before further using it. e.g. requires to check IOMMU UAPI support. Referred patch from Eric Auger: https://patchwork.kernel.org/patch/11040499/ Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Alex Williamson Signed-off-by: Liu Yi L Signed-off-by: Eric Auger Signed-off-by: Yi Sun --- hw/vfio/common.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 44097875e2..883815d5b0 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1543,30 +1543,44 @@ static void vfio_put_address_space(VFIOAddressSpace *space) } /* - * vfio_get_iommu_type - selects the richest iommu_type (v2 first) + * vfio_get_iommu_type - selects the richest iommu_type (NESTING first) */ static int vfio_get_iommu_type(VFIOContainer *container, + bool want_nested, Error **errp) { - int iommu_types[] = { VFIO_TYPE1v2_IOMMU, VFIO_TYPE1_IOMMU, + int iommu_types[] = { VFIO_TYPE1_NESTING_IOMMU, + VFIO_TYPE1v2_IOMMU, VFIO_TYPE1_IOMMU, VFIO_SPAPR_TCE_v2_IOMMU, VFIO_SPAPR_TCE_IOMMU }; - int i; + int i, ret = -EINVAL; for (i = 0; i < ARRAY_SIZE(iommu_types); i++) { if (ioctl(container->fd, VFIO_CHECK_EXTENSION, iommu_types[i])) { - return iommu_types[i]; + if (iommu_types[i] == VFIO_TYPE1_NESTING_IOMMU) { + if (!want_nested) { + continue; + } + } + ret = iommu_types[i]; + break; } } - error_setg(errp, "No available IOMMU models"); - return -EINVAL; + + if (ret < 0) { + error_setg(errp, "No available IOMMU models"); + } else if (want_nested && ret != VFIO_TYPE1_NESTING_IOMMU) { + error_setg(errp, "Nested mode requested but not supported"); + ret = -EINVAL; + } + return ret; } static int vfio_init_container(VFIOContainer *container, int group_fd, - Error **errp) + bool want_nested, Error **errp) { int iommu_type, ret; - iommu_type = vfio_get_iommu_type(container, errp); + iommu_type = vfio_get_iommu_type(container, want_nested, errp); if (iommu_type < 0) { return iommu_type; } @@ -1666,7 +1680,7 @@ static void vfio_get_iommu_info_migration(VFIOContainer *container, } static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - Error **errp) + bool want_nested, Error **errp) { VFIOContainer *container; int ret, fd; @@ -1738,12 +1752,13 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, QLIST_INIT(&container->giommu_list); QLIST_INIT(&container->hostwin_list); - ret = vfio_init_container(container, group->fd, errp); + ret = vfio_init_container(container, group->fd, want_nested, errp); if (ret) { goto free_container_exit; } switch (container->iommu_type) { + case VFIO_TYPE1_NESTING_IOMMU: case VFIO_TYPE1v2_IOMMU: case VFIO_TYPE1_IOMMU: { @@ -1968,7 +1983,7 @@ VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, group->groupid = groupid; QLIST_INIT(&group->device_list); - if (vfio_connect_container(group, as, errp)) { + if (vfio_connect_container(group, as, want_nested, errp)) { error_prepend(errp, "failed to setup container for group %d: ", groupid); goto close_fd_exit; From patchwork Tue Mar 2 20:38:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446011 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcKC1fMYz9sS8 for ; Tue, 2 Mar 2021 23:44:47 +1100 (AEDT) Received: from localhost ([::1]:45408 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4OL-00038H-7N for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:44:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:32848) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4K0-0007XC-33 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:16 -0500 Received: from mga04.intel.com ([192.55.52.120]:29709) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Jx-0002i5-8E for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:15 -0500 IronPort-SDR: sVddiIOz0YJvEUlddHbMk8jS4zPh7ydbE+HUyF6ZzWUsbOC6AZ/umK6n82NOvsL4OWK+CM5mFx NVynT8Klk7TA== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="184363283" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="184363283" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:09 -0800 IronPort-SDR: HZKQJN3zIWAsIqymBvFgDKWmw2o5mFSLHVNhu4ud6gxffL8m1nBtPyWQi4qqxOgwRqXGI0iMxg dqCQU/Cp4CqQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472839" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:03 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 09/25] hw/iommu: introduce HostIOMMUContext Date: Wed, 3 Mar 2021 04:38:11 +0800 Message-Id: <20210302203827.437645-10-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.120; envelope-from=yi.l.liu@intel.com; helo=mga04.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Currently, many platform vendors provide the capability of dual stage DMA address translation in hardware. For example, nested translation on Intel VT-d scalable mode, nested stage translation on ARM SMMUv3, and etc. In dual stage DMA address translation, there are two stages address translation, stage-1 (a.k.a first-level) and stage-2 (a.k.a second-level) translation structures. Stage-1 translation results are also subjected to stage-2 translation structures. Take vSVA (Virtual Shared Virtual Addressing) as an example, guest IOMMU driver owns stage-1 translation structures (covers GVA->GPA translation), and host IOMMU driver owns stage-2 translation structures (covers GPA->HPA translation). VMM is responsible to bind stage-1 translation structures to host, thus hardware could achieve GVA->GPA and then GPA->HPA translation. For more background on SVA, refer the below links. - https://www.youtube.com/watch?v=Kq_nfGK5MwQ - https://events19.lfasiallc.com/wp-content/uploads/2017/11/Shared-Virtual-Memory-in-KVM_Yi-Liu.pdf In QEMU, vIOMMU emulators expose IOMMUs to VM per their own spec (e.g. Intel VT-d spec). Devices are pass-through to guest via device pass- through components like VFIO. VFIO is a userspace driver framework which exposes host IOMMU programming capability to userspace in a secure manner. e.g. IOVA MAP/UNMAP requests. Information, different from map/unmap notifications need to be passed from QEMU vIOMMU device to/from the host IOMMU driver through the VFIO/IOMMU layer: 1) bind stage-1 translation structures to host 2) propagate stage-1 cache invalidation to host 3) DMA address translation fault (I/O page fault) servicing etc. With the above new interactions in QEMU, it requires an abstract layer to facilitate the above operations and expose to vIOMMU emulators as an explicit way for vIOMMU emulators call into VFIO. This patch introduces HostIOMMUContext to serve it. The HostIOMMUContext is an object which allows to manage the stage-1 translation when a vIOMMU is implemented upon physical IOMMU nested paging (VFIO case). It is an abstract object which needs to be derived for each vIOMMU immplementation based on physical nested paging. An HostIOMMUContext derived object will be passed to each VFIO device protected by a vIOMMU using physical nested paging. This patch also introduces HostIOMMUContextClass to provide methods for vIOMMU emulators to propagate dual-stage translation related requests to host. As a beginning, bind_stage1_pgtbl/unbind_stage1_pgtbl() were defined for configuring vIOMMU's page table to host. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Michael S. Tsirkin Signed-off-by: Liu Yi L --- rfcv10 -> rfcv11: *) removed pasid_alloc/free in HostIOMMUContextClass, define bind_stage1_pgtbl and unbind_stage1_pgtbl() as a start for HostIOMMUContextClass. rfcv9 -> rfcv10: *) adjust to meson build --- hw/Kconfig | 3 + hw/iommu/Kconfig | 4 + hw/iommu/host_iommu_context.c | 106 ++++++++++++++++++++++++++ hw/iommu/meson.build | 6 ++ hw/meson.build | 1 + include/hw/iommu/host_iommu_context.h | 75 ++++++++++++++++++ 6 files changed, 195 insertions(+) create mode 100644 hw/iommu/Kconfig create mode 100644 hw/iommu/host_iommu_context.c create mode 100644 hw/iommu/meson.build create mode 100644 include/hw/iommu/host_iommu_context.h diff --git a/hw/Kconfig b/hw/Kconfig index 8ea26479c4..fc660790f1 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -66,6 +66,9 @@ source tricore/Kconfig source unicore32/Kconfig source xtensa/Kconfig +# iommu Kconfig +source iommu/Kconfig + # Symbols used by multiple targets config TEST_DEVICES bool diff --git a/hw/iommu/Kconfig b/hw/iommu/Kconfig new file mode 100644 index 0000000000..039b9a4caf --- /dev/null +++ b/hw/iommu/Kconfig @@ -0,0 +1,4 @@ +config IOMMU + bool + default y + depends on LINUX diff --git a/hw/iommu/host_iommu_context.c b/hw/iommu/host_iommu_context.c new file mode 100644 index 0000000000..d7139bcb86 --- /dev/null +++ b/hw/iommu/host_iommu_context.c @@ -0,0 +1,106 @@ +/* + * QEMU abstract of Host IOMMU + * + * Copyright (C) 2020 Intel Corporation. + * + * Authors: Liu Yi L + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qom/object.h" +#include "qapi/visitor.h" +#include "hw/iommu/host_iommu_context.h" + +int host_iommu_ctx_bind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, + struct iommu_gpasid_bind_data *bind) +{ + HostIOMMUContextClass *hicxc; + + if (!iommu_ctx) { + return -EINVAL; + } + + hicxc = HOST_IOMMU_CONTEXT_GET_CLASS(iommu_ctx); + if (!hicxc) { + return -EINVAL; + } + + if (!(iommu_ctx->info->features & IOMMU_NESTING_FEAT_BIND_PGTBL) || + !hicxc->bind_stage1_pgtbl) { + return -EINVAL; + } + + return hicxc->bind_stage1_pgtbl(iommu_ctx, bind); +} + +int host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, + struct iommu_gpasid_bind_data *unbind) +{ + HostIOMMUContextClass *hicxc; + + if (!iommu_ctx) { + return -EINVAL; + } + + hicxc = HOST_IOMMU_CONTEXT_GET_CLASS(iommu_ctx); + if (!hicxc) { + return -EINVAL; + } + + if (!(iommu_ctx->info->features & IOMMU_NESTING_FEAT_BIND_PGTBL) || + !hicxc->unbind_stage1_pgtbl) { + return -EINVAL; + } + + return hicxc->unbind_stage1_pgtbl(iommu_ctx, unbind); +} + +void host_iommu_ctx_init(void *_iommu_ctx, size_t instance_size, + const char *mrtypename, + struct iommu_nesting_info *info) +{ + HostIOMMUContext *iommu_ctx; + + object_initialize(_iommu_ctx, instance_size, mrtypename); + iommu_ctx = HOST_IOMMU_CONTEXT(_iommu_ctx); + iommu_ctx->info = g_malloc0(info->argsz); + memcpy(iommu_ctx->info, info, info->argsz); + iommu_ctx->initialized = true; +} + +static void host_iommu_ctx_finalize_fn(Object *obj) +{ + HostIOMMUContext *iommu_ctx = HOST_IOMMU_CONTEXT(obj); + + g_free(iommu_ctx->info); +} + +static const TypeInfo host_iommu_context_info = { + .parent = TYPE_OBJECT, + .name = TYPE_HOST_IOMMU_CONTEXT, + .class_size = sizeof(HostIOMMUContextClass), + .instance_size = sizeof(HostIOMMUContext), + .instance_finalize = host_iommu_ctx_finalize_fn, + .abstract = true, +}; + +static void host_iommu_ctx_register_types(void) +{ + type_register_static(&host_iommu_context_info); +} + +type_init(host_iommu_ctx_register_types) diff --git a/hw/iommu/meson.build b/hw/iommu/meson.build new file mode 100644 index 0000000000..acf72acc4c --- /dev/null +++ b/hw/iommu/meson.build @@ -0,0 +1,6 @@ +iommu_ss = ss.source_set() +iommu_ss.add(files( + 'host_iommu_context.c', +)) + +specific_ss.add_all(when: 'CONFIG_IOMMU', if_true: iommu_ss) diff --git a/hw/meson.build b/hw/meson.build index e615d72d4d..1370b1e79e 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -66,3 +66,4 @@ subdir('sparc64') subdir('tricore') subdir('unicore32') subdir('xtensa') +subdir('iommu') diff --git a/include/hw/iommu/host_iommu_context.h b/include/hw/iommu/host_iommu_context.h new file mode 100644 index 0000000000..41c4176c15 --- /dev/null +++ b/include/hw/iommu/host_iommu_context.h @@ -0,0 +1,75 @@ +/* + * QEMU abstraction of Host IOMMU + * + * Copyright (C) 2020 Intel Corporation. + * + * Authors: Liu Yi L + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_IOMMU_CONTEXT_H +#define HW_IOMMU_CONTEXT_H + +#include "qemu/queue.h" +#include "qemu/thread.h" +#include "qom/object.h" +#include +#ifndef CONFIG_USER_ONLY +#include "exec/hwaddr.h" +#endif + +#define TYPE_HOST_IOMMU_CONTEXT "qemu:host-iommu-context" +#define HOST_IOMMU_CONTEXT(obj) \ + OBJECT_CHECK(HostIOMMUContext, (obj), TYPE_HOST_IOMMU_CONTEXT) +#define HOST_IOMMU_CONTEXT_GET_CLASS(obj) \ + OBJECT_GET_CLASS(HostIOMMUContextClass, (obj), \ + TYPE_HOST_IOMMU_CONTEXT) + +typedef struct HostIOMMUContext HostIOMMUContext; + +typedef struct HostIOMMUContextClass { + /* private */ + ObjectClass parent_class; + /* + * Bind stage-1 page table to a hostIOMMU w/ dual stage + * DMA translation capability. + * @bind specifies the bind configurations. + */ + int (*bind_stage1_pgtbl)(HostIOMMUContext *iommu_ctx, + struct iommu_gpasid_bind_data *bind); + /* Undo a previous bind. @unbind specifies the unbind info. */ + int (*unbind_stage1_pgtbl)(HostIOMMUContext *iommu_ctx, + struct iommu_gpasid_bind_data *unbind); +} HostIOMMUContextClass; + +/* + * This is an abstraction of host IOMMU with dual-stage capability + */ +struct HostIOMMUContext { + Object parent_obj; + struct iommu_nesting_info *info; + bool initialized; +}; + +int host_iommu_ctx_bind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, + struct iommu_gpasid_bind_data *bind); +int host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, + struct iommu_gpasid_bind_data *unbind); +void host_iommu_ctx_init(void *_iommu_ctx, size_t instance_size, + const char *mrtypename, + struct iommu_nesting_info *info); +void host_iommu_ctx_destroy(HostIOMMUContext *iommu_ctx); + +#endif From patchwork Tue Mar 2 20:38:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446024 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcVb1nB0z9sVt for ; Tue, 2 Mar 2021 23:52:55 +1100 (AEDT) Received: from localhost ([::1]:39870 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4WD-0004fQ-5E for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:52:53 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:32868) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4K1-0007Zk-7C for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:17 -0500 Received: from mga04.intel.com ([192.55.52.120]:29715) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Jy-0002id-T0 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:16 -0500 IronPort-SDR: v64n1hbLKbdNVhtYZ3iJUfCS7+/pd9POdxplayKGIgEBH3zEyY7rCHhtp3MtEs4ItRqNvGSJPz V1p0H4x+ukPg== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="184363339" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="184363339" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:13 -0800 IronPort-SDR: sjNnsxyGkIrkvlER1z4ffCndPPpwtAtDUKWDoWIJq7tsocpPc2jLG3lPqLPlRbaYvjSOiBR9V0 nB8wbAnslHAA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472861" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:09 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 10/25] hw/pci: introduce pci_device_set/unset_iommu_context() Date: Wed, 3 Mar 2021 04:38:12 +0800 Message-Id: <20210302203827.437645-11-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.120; envelope-from=yi.l.liu@intel.com; helo=mga04.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" For nesting IOMMU translation capable platforms, vIOMMUs running on such system could be implemented upon physical IOMMU nested paging (VFIO case). vIOMMU advertises such implementation by "want_nested" attribute to PCIe devices (e.g. VFIO PCI). Once "want_nested" is satisfied, device (VFIO case) should set HostIOMMUContext to vIOMMU, thus vIOMMU could manage stage-1 translation. DMAs out from such devices would be protected through the stage-1 page tables owned by guest together with stage-2 page tables owned by host. This patch adds pci_device_set/unset_iommu_context() to set/unset HostIOMMUContext for a given PCIe device (VFIO case). Caller of set should fail if set operation failed. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Michael S. Tsirkin Reviewed-by: Peter Xu Signed-off-by: Liu Yi L --- rfcv5 (v2) -> rfcv6: *) pci_device_set_iommu_context() returns 0 if callback is not implemented. --- hw/pci/pci.c | 28 ++++++++++++++++++++++++++++ include/hw/pci/pci.h | 10 ++++++++++ 2 files changed, 38 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 19365e2799..a2c270a5d6 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2749,6 +2749,34 @@ int pci_device_get_iommu_attr(PCIDevice *dev, IOMMUAttr attr, void *data) return -ENOENT; } +int pci_device_set_iommu_context(PCIDevice *dev, + HostIOMMUContext *iommu_ctx) +{ + PCIBus *bus; + uint8_t devfn; + + pci_device_get_iommu_bus_devfn(dev, &bus, &devfn); + if (bus && bus->iommu_ops && + bus->iommu_ops->set_iommu_context) { + return bus->iommu_ops->set_iommu_context(bus, + bus->iommu_opaque, devfn, iommu_ctx); + } + return 0; +} + +void pci_device_unset_iommu_context(PCIDevice *dev) +{ + PCIBus *bus; + uint8_t devfn; + + pci_device_get_iommu_bus_devfn(dev, &bus, &devfn); + if (bus && bus->iommu_ops && + bus->iommu_ops->unset_iommu_context) { + bus->iommu_ops->unset_iommu_context(bus, + bus->iommu_opaque, devfn); + } +} + void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque) { bus->iommu_ops = ops; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index b99e05c81e..1eeb177f4f 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -10,6 +10,8 @@ #include "hw/pci/pcie.h" #include "qom/object.h" +#include "hw/iommu/host_iommu_context.h" + extern bool pci_available; /* PCI bus */ @@ -495,10 +497,18 @@ struct PCIIOMMUOps { void *opaque, int32_t devfn); int (*get_iommu_attr)(PCIBus *bus, void *opaque, int32_t devfn, IOMMUAttr attr, void *data); + int (*set_iommu_context)(PCIBus *bus, void *opaque, + int32_t devfn, + HostIOMMUContext *iommu_ctx); + void (*unset_iommu_context)(PCIBus *bus, void *opaque, + int32_t devfn); }; AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); int pci_device_get_iommu_attr(PCIDevice *dev, IOMMUAttr attr, void *data); +int pci_device_set_iommu_context(PCIDevice *dev, + HostIOMMUContext *iommu_ctx); +void pci_device_unset_iommu_context(PCIDevice *dev); void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *iommu_ops, void *opaque); static inline void From patchwork Tue Mar 2 20:38:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446025 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcW36d4Jz9sVw for ; Tue, 2 Mar 2021 23:53:19 +1100 (AEDT) Received: from localhost ([::1]:41758 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4Wb-0005TY-II for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:53:17 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:32966) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4K8-0007hV-L2 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:24 -0500 Received: from mga05.intel.com ([192.55.52.43]:62468) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4K6-0002nT-7O for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:24 -0500 IronPort-SDR: 12qEz89+YD9RqX4f9Ewru3x/RJYlHkCHBu1lwwleOTbH2oywIhi6gnLaNuMJUsEVzyV13IFJpi bX+HCB+uIr0g== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="271803059" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="271803059" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:20 -0800 IronPort-SDR: Z2ydfC+vTLoozXz6uRkgrWtTwdhKWlHy4iGxy4tQ0HdPy+TZ5NUyM1AhipSdDqSwxjw5+CDmtm W4TLz/IcxWSw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472895" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:13 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 11/25] intel_iommu: add set/unset_iommu_context callback Date: Wed, 3 Mar 2021 04:38:13 +0800 Message-Id: <20210302203827.437645-12-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.43; envelope-from=yi.l.liu@intel.com; helo=mga05.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds set/unset_iommu_context() impelementation in Intel vIOMMU. PCIe devices (VFIO case) sets HostIOMMUContext to vIOMMU as an ack of vIOMMU's "want_nested" attribute. Thus vIOMMU could build DMA protection based on nested paging of host IOMMU. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Liu Yi L --- hw/i386/intel_iommu.c | 71 ++++++++++++++++++++++++++++++++--- include/hw/i386/intel_iommu.h | 21 +++++++++-- 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index d89d6d7dd5..8419fd2818 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3380,23 +3380,33 @@ static const MemoryRegionOps vtd_mem_ir_ops = { }, }; -VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) +/** + * Fetch a VTDBus instance for given PCIBus. If no existing instance, + * allocate one. + */ +static VTDBus *vtd_find_add_bus(IntelIOMMUState *s, PCIBus *bus) { uintptr_t key = (uintptr_t)bus; VTDBus *vtd_bus = g_hash_table_lookup(s->vtd_as_by_busptr, &key); - VTDAddressSpace *vtd_dev_as; - char name[128]; if (!vtd_bus) { uintptr_t *new_key = g_malloc(sizeof(*new_key)); *new_key = (uintptr_t)bus; /* No corresponding free() */ - vtd_bus = g_malloc0(sizeof(VTDBus) + sizeof(VTDAddressSpace *) * \ - PCI_DEVFN_MAX); + vtd_bus = g_malloc0(sizeof(VTDBus)); vtd_bus->bus = bus; g_hash_table_insert(s->vtd_as_by_busptr, new_key, vtd_bus); } + return vtd_bus; +} +VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) +{ + VTDBus *vtd_bus; + VTDAddressSpace *vtd_dev_as; + char name[128]; + + vtd_bus = vtd_find_add_bus(s, bus); vtd_dev_as = vtd_bus->dev_as[devfn]; if (!vtd_dev_as) { @@ -3484,6 +3494,55 @@ static int vtd_dev_get_iommu_attr(PCIBus *bus, void *opaque, int32_t devfn, return ret; } +static int vtd_dev_set_iommu_context(PCIBus *bus, void *opaque, + int devfn, + HostIOMMUContext *iommu_ctx) +{ + IntelIOMMUState *s = opaque; + VTDBus *vtd_bus; + VTDHostIOMMUContext *vtd_dev_icx; + + assert(0 <= devfn && devfn < PCI_DEVFN_MAX); + + vtd_bus = vtd_find_add_bus(s, bus); + + vtd_iommu_lock(s); + + vtd_dev_icx = vtd_bus->dev_icx[devfn]; + + assert(!vtd_dev_icx); + + vtd_bus->dev_icx[devfn] = vtd_dev_icx = + g_malloc0(sizeof(VTDHostIOMMUContext)); + vtd_dev_icx->vtd_bus = vtd_bus; + vtd_dev_icx->devfn = (uint8_t)devfn; + vtd_dev_icx->iommu_state = s; + vtd_dev_icx->iommu_ctx = iommu_ctx; + + vtd_iommu_unlock(s); + + return 0; +} + +static void vtd_dev_unset_iommu_context(PCIBus *bus, void *opaque, int devfn) +{ + IntelIOMMUState *s = opaque; + VTDBus *vtd_bus; + VTDHostIOMMUContext *vtd_dev_icx; + + assert(0 <= devfn && devfn < PCI_DEVFN_MAX); + + vtd_bus = vtd_find_add_bus(s, bus); + + vtd_iommu_lock(s); + + vtd_dev_icx = vtd_bus->dev_icx[devfn]; + g_free(vtd_dev_icx); + vtd_bus->dev_icx[devfn] = NULL; + + vtd_iommu_unlock(s); +} + static uint64_t get_naturally_aligned_size(uint64_t start, uint64_t size, int gaw) { @@ -3781,6 +3840,8 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) static PCIIOMMUOps vtd_iommu_ops = { .get_address_space = vtd_host_dma_iommu, .get_iommu_attr = vtd_dev_get_iommu_attr, + .set_iommu_context = vtd_dev_set_iommu_context, + .unset_iommu_context = vtd_dev_unset_iommu_context, }; static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 41783ee46d..28396675ef 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -63,6 +63,7 @@ typedef union VTD_IR_TableEntry VTD_IR_TableEntry; typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress; typedef struct VTDPASIDDirEntry VTDPASIDDirEntry; typedef struct VTDPASIDEntry VTDPASIDEntry; +typedef struct VTDHostIOMMUContext VTDHostIOMMUContext; /* Context-Entry */ struct VTDContextEntry { @@ -111,10 +112,20 @@ struct VTDAddressSpace { IOVATree *iova_tree; /* Traces mapped IOVA ranges */ }; +struct VTDHostIOMMUContext { + VTDBus *vtd_bus; + uint8_t devfn; + HostIOMMUContext *iommu_ctx; + IntelIOMMUState *iommu_state; +}; + struct VTDBus { - PCIBus* bus; /* A reference to the bus to provide translation for */ + /* A reference to the bus to provide translation for */ + PCIBus *bus; /* A table of VTDAddressSpace objects indexed by devfn */ - VTDAddressSpace *dev_as[]; + VTDAddressSpace *dev_as[PCI_DEVFN_MAX]; + /* A table of VTDHostIOMMUContext objects indexed by devfn */ + VTDHostIOMMUContext *dev_icx[PCI_DEVFN_MAX]; }; struct VTDIOTLBEntry { @@ -268,8 +279,10 @@ struct IntelIOMMUState { bool dma_drain; /* Whether DMA r/w draining enabled */ /* - * Protects IOMMU states in general. Currently it protects the - * per-IOMMU IOTLB cache, and context entry cache in VTDAddressSpace. + * iommu_lock protects below: + * - per-IOMMU IOTLB caches + * - context entry cache in VTDAddressSpace + * - HostIOMMUContext pointer cached in vIOMMU */ QemuMutex iommu_lock; }; From patchwork Tue Mar 2 20:38:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446029 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcYX3rMlz9sS8 for ; Tue, 2 Mar 2021 23:55:28 +1100 (AEDT) Received: from localhost ([::1]:49604 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4Yg-0000IO-I5 for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:55:26 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33002) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KB-0007jp-VL for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:28 -0500 Received: from mga05.intel.com ([192.55.52.43]:62468) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KA-0002nT-2P for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:27 -0500 IronPort-SDR: SGIqMdRTmlIyO1dy71edT40ugJ3qJ7iY02v0f8t+FurgzkEojTbJnLJo2roc+AAEeSlhKYA5r9 fpHxgs996rOQ== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="271803101" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="271803101" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:25 -0800 IronPort-SDR: 3m2tH7iTtFMEWJ1fNEtLOwW5jsZf0m2Tm6vYxUwFZllkkL72c4tFJWJLN3nHDOWSdjpTDEyAty eT6FiT3EfZxA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472924" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:20 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 12/25] vfio: add HostIOMMUContext support Date: Wed, 3 Mar 2021 04:38:14 +0800 Message-Id: <20210302203827.437645-13-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.43; envelope-from=yi.l.liu@intel.com; helo=mga05.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds support for HostIOMMUContext, implements bind_stage1_pgtbl() and unbind_stage1_pgtbl() for vIOMMU to setup dual stage DMA translation for passthru devices on hardware. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Alex Williamson Signed-off-by: Liu Yi L --- hw/vfio/common.c | 70 +++++++++++++++++++++++++++ include/hw/iommu/host_iommu_context.h | 3 ++ include/hw/vfio/vfio-common.h | 3 ++ 3 files changed, 76 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 883815d5b0..433938c245 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1575,6 +1575,54 @@ static int vfio_get_iommu_type(VFIOContainer *container, return ret; } +static int vfio_host_iommu_ctx_bind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, + struct iommu_gpasid_bind_data *bind) +{ + VFIOContainer *container = container_of(iommu_ctx, + VFIOContainer, iommu_ctx); + struct vfio_iommu_type1_nesting_op *op; + unsigned long argsz; + int ret = 0; + + argsz = sizeof(*op) + sizeof(*bind); + op = g_malloc0(argsz); + op->argsz = argsz; + op->flags = VFIO_IOMMU_NESTING_OP_BIND_PGTBL; + memcpy(&op->data, bind, sizeof(*bind)); + + if (ioctl(container->fd, VFIO_IOMMU_NESTING_OP, op)) { + ret = -errno; + error_report("%s: pasid (%llu) bind failed: %m", + __func__, bind->hpasid); + } + g_free(op); + return ret; +} + +static int vfio_host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, + struct iommu_gpasid_bind_data *unbind) +{ + VFIOContainer *container = container_of(iommu_ctx, + VFIOContainer, iommu_ctx); + struct vfio_iommu_type1_nesting_op *op; + unsigned long argsz; + int ret = 0; + + argsz = sizeof(*op) + sizeof(*unbind); + op = g_malloc0(argsz); + op->argsz = argsz; + op->flags = VFIO_IOMMU_NESTING_OP_UNBIND_PGTBL; + memcpy(&op->data, unbind, sizeof(*unbind)); + + if (ioctl(container->fd, VFIO_IOMMU_NESTING_OP, op)) { + ret = -errno; + error_report("%s: pasid (%llu) unbind failed: %m", + __func__, unbind->hpasid); + } + g_free(op); + return ret; +} + static int vfio_init_container(VFIOContainer *container, int group_fd, bool want_nested, Error **errp) { @@ -2268,3 +2316,25 @@ int vfio_eeh_as_op(AddressSpace *as, uint32_t op) } return vfio_eeh_container_op(container, op); } + +static void vfio_host_iommu_context_class_init(ObjectClass *klass, + void *data) +{ + HostIOMMUContextClass *hicxc = HOST_IOMMU_CONTEXT_CLASS(klass); + + hicxc->bind_stage1_pgtbl = vfio_host_iommu_ctx_bind_stage1_pgtbl; + hicxc->unbind_stage1_pgtbl = vfio_host_iommu_ctx_unbind_stage1_pgtbl; +} + +static const TypeInfo vfio_host_iommu_context_info = { + .parent = TYPE_HOST_IOMMU_CONTEXT, + .name = TYPE_VFIO_HOST_IOMMU_CONTEXT, + .class_init = vfio_host_iommu_context_class_init, +}; + +static void vfio_register_types(void) +{ + type_register_static(&vfio_host_iommu_context_info); +} + +type_init(vfio_register_types) diff --git a/include/hw/iommu/host_iommu_context.h b/include/hw/iommu/host_iommu_context.h index 41c4176c15..3498a3e25d 100644 --- a/include/hw/iommu/host_iommu_context.h +++ b/include/hw/iommu/host_iommu_context.h @@ -33,6 +33,9 @@ #define TYPE_HOST_IOMMU_CONTEXT "qemu:host-iommu-context" #define HOST_IOMMU_CONTEXT(obj) \ OBJECT_CHECK(HostIOMMUContext, (obj), TYPE_HOST_IOMMU_CONTEXT) +#define HOST_IOMMU_CONTEXT_CLASS(klass) \ + OBJECT_CLASS_CHECK(HostIOMMUContextClass, (klass), \ + TYPE_HOST_IOMMU_CONTEXT) #define HOST_IOMMU_CONTEXT_GET_CLASS(obj) \ OBJECT_GET_CLASS(HostIOMMUContextClass, (obj), \ TYPE_HOST_IOMMU_CONTEXT) diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 293d3785f3..55241ee270 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -26,6 +26,7 @@ #include "qemu/notify.h" #include "ui/console.h" #include "hw/display/ramfb.h" +#include "hw/iommu/host_iommu_context.h" #ifdef CONFIG_LINUX #include #endif @@ -33,6 +34,8 @@ #define VFIO_MSG_PREFIX "vfio %s: " +#define TYPE_VFIO_HOST_IOMMU_CONTEXT "qemu:vfio-host-iommu-context" + enum { VFIO_DEVICE_TYPE_PCI = 0, VFIO_DEVICE_TYPE_PLATFORM = 1, From patchwork Tue Mar 2 20:38:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446031 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcbX074Jz9sS8 for ; Tue, 2 Mar 2021 23:57:11 +1100 (AEDT) Received: from localhost ([::1]:54218 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4aL-0002Q9-AJ for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:57:09 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33048) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KG-0007sh-O8 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:32 -0500 Received: from mga05.intel.com ([192.55.52.43]:62468) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KE-0002nT-CB for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:32 -0500 IronPort-SDR: 8wC4Z6XACe+XY47Sq2mfk2GtnvQakkmx7AXxdFasE4noT+5FaLCjrFYsmtzuF3UtAyVL+m9pM6 hoOfjRDL3QTQ== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="271803131" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="271803131" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:29 -0800 IronPort-SDR: 2rBwXi9CGAqzBAfgjGa2/z9Z7RLcfK9+aaBOHTgVIBWhWDpMD0yV419aGiITwQLR0Jexxae9Nv r47dGVFbNZGQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472958" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:25 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 13/25] vfio: init HostIOMMUContext per-container Date: Wed, 3 Mar 2021 04:38:15 +0800 Message-Id: <20210302203827.437645-14-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.43; envelope-from=yi.l.liu@intel.com; helo=mga05.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" In this patch, QEMU firstly gets iommu info from kernel to check the supported capabilities by a VFIO_IOMMU_TYPE1_NESTING iommu. And inits HostIOMMUContet instance. For vfio-pci devices, it could use pci_device_set/unset_iommu() to expose host iommu context to vIOMMU emulators. vIOMMU emulators could make use of the methods provided by host iommu context. e.g. propagate requests to host iommu. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Alex Williamson Signed-off-by: Liu Yi L --- hw/vfio/common.c | 135 +++++++++++++++++++++++++--------- hw/vfio/pci.c | 17 +++++ include/hw/vfio/vfio-common.h | 1 + 3 files changed, 118 insertions(+), 35 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 433938c245..a12708bcb7 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1623,41 +1623,11 @@ static int vfio_host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, return ret; } -static int vfio_init_container(VFIOContainer *container, int group_fd, - bool want_nested, Error **errp) -{ - int iommu_type, ret; - - iommu_type = vfio_get_iommu_type(container, want_nested, errp); - if (iommu_type < 0) { - return iommu_type; - } - - ret = ioctl(group_fd, VFIO_GROUP_SET_CONTAINER, &container->fd); - if (ret) { - error_setg_errno(errp, errno, "Failed to set group container"); - return -errno; - } - - while (ioctl(container->fd, VFIO_SET_IOMMU, iommu_type)) { - if (iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - /* - * On sPAPR, despite the IOMMU subdriver always advertises v1 and - * v2, the running platform may not support v2 and there is no - * way to guess it until an IOMMU group gets added to the container. - * So in case it fails with v2, try v1 as a fallback. - */ - iommu_type = VFIO_SPAPR_TCE_IOMMU; - continue; - } - error_setg_errno(errp, errno, "Failed to set iommu for container"); - return -errno; - } - - container->iommu_type = iommu_type; - return 0; -} - +/** + * Get iommu info from host. Caller of this funcion should free + * the memory pointed by the returned pointer stored in @info + * after a successful calling when finished its usage. + */ static int vfio_get_iommu_info(VFIOContainer *container, struct vfio_iommu_type1_info **info) { @@ -1702,6 +1672,101 @@ vfio_get_iommu_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) return NULL; } +static int vfio_get_nesting_iommu_cap(VFIOContainer *container, + struct vfio_iommu_type1_info_cap_nesting **cap_nesting) +{ + struct vfio_iommu_type1_info *info; + struct vfio_info_cap_header *hdr; + struct vfio_iommu_type1_info_cap_nesting *cap; + struct iommu_nesting_info *nest_info; + int ret; + uint32_t minsz, cap_size; + + ret = vfio_get_iommu_info(container, &info); + if (ret) { + return ret; + } + + hdr = vfio_get_iommu_info_cap(info, + VFIO_IOMMU_TYPE1_INFO_CAP_NESTING); + if (!hdr) { + g_free(info); + return -EINVAL; + } + + cap = container_of(hdr, + struct vfio_iommu_type1_info_cap_nesting, header); + + nest_info = &cap->info; + minsz = offsetof(struct iommu_nesting_info, vendor); + if (nest_info->argsz < minsz) { + g_free(info); + return -EINVAL; + } + + cap_size = offsetof(struct vfio_iommu_type1_info_cap_nesting, info) + + nest_info->argsz; + *cap_nesting = g_malloc0(cap_size); + memcpy(*cap_nesting, cap, cap_size); + + g_free(info); + return 0; +} + +static int vfio_init_container(VFIOContainer *container, int group_fd, + bool want_nested, Error **errp) +{ + int iommu_type, ret; + + iommu_type = vfio_get_iommu_type(container, want_nested, errp); + if (iommu_type < 0) { + return iommu_type; + } + + ret = ioctl(group_fd, VFIO_GROUP_SET_CONTAINER, &container->fd); + if (ret) { + error_setg_errno(errp, errno, "Failed to set group container"); + return -errno; + } + + while (ioctl(container->fd, VFIO_SET_IOMMU, iommu_type)) { + if (iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { + /* + * On sPAPR, despite the IOMMU subdriver always advertises v1 and + * v2, the running platform may not support v2 and there is no + * way to guess it until an IOMMU group gets added to the container. + * So in case it fails with v2, try v1 as a fallback. + */ + iommu_type = VFIO_SPAPR_TCE_IOMMU; + continue; + } + error_setg_errno(errp, errno, "Failed to set iommu for container"); + return -errno; + } + + if (iommu_type == VFIO_TYPE1_NESTING_IOMMU) { + struct vfio_iommu_type1_info_cap_nesting *nesting = NULL; + struct iommu_nesting_info *nest_info; + + ret = vfio_get_nesting_iommu_cap(container, &nesting); + if (ret) { + error_setg_errno(errp, -ret, + "Failed to get nesting iommu cap"); + return ret; + } + + nest_info = (struct iommu_nesting_info *) &nesting->info; + host_iommu_ctx_init(&container->iommu_ctx, + sizeof(container->iommu_ctx), + TYPE_VFIO_HOST_IOMMU_CONTEXT, + nest_info); + g_free(nesting); + } + + container->iommu_type = iommu_type; + return 0; +} + static void vfio_get_iommu_info_migration(VFIOContainer *container, struct vfio_iommu_type1_info *info) { diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 437f51338e..f5363589b6 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2764,6 +2764,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) VFIOPCIDevice *vdev = VFIO_PCI(pdev); VFIODevice *vbasedev_iter; VFIOGroup *group; + VFIOContainer *container; char *tmp, *subsys, group_path[PATH_MAX], *group_name; Error *err = NULL; ssize_t len; @@ -2829,6 +2830,15 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } + container = group->container; + if (container->iommu_ctx.initialized && + pci_device_set_iommu_context(pdev, &container->iommu_ctx)) { + error_setg(errp, "device attachment is denied by vIOMMU, " + "please check host IOMMU nesting capability"); + vfio_put_group(group); + goto error; + } + QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) { error_setg(errp, "device is already attached"); @@ -3112,9 +3122,16 @@ static void vfio_instance_finalize(Object *obj) static void vfio_exitfn(PCIDevice *pdev) { VFIOPCIDevice *vdev = VFIO_PCI(pdev); + VFIOContainer *container; vfio_unregister_req_notifier(vdev); vfio_unregister_err_notifier(vdev); + + container = vdev->vbasedev.group->container; + if (container->iommu_ctx.initialized) { + pci_device_unset_iommu_context(pdev); + } + pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); if (vdev->irqchip_change_notifier.notify) { kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 55241ee270..5a9f2b6325 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -85,6 +85,7 @@ typedef struct VFIOContainer { MemoryListener listener; MemoryListener prereg_listener; unsigned iommu_type; + HostIOMMUContext iommu_ctx; Error *error; bool initialized; bool dirty_pages_supported; From patchwork Tue Mar 2 20:38:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446012 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcKC6GQJz9sVt for ; Tue, 2 Mar 2021 23:44:47 +1100 (AEDT) Received: from localhost ([::1]:45578 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4OL-0003Ce-SJ for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:44:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33082) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KN-0007yG-6p for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:40 -0500 Received: from mga05.intel.com ([192.55.52.43]:62468) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KJ-0002nT-06 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:38 -0500 IronPort-SDR: vFD+s7bc6oYoYuIM3Z76C+1Zd+wi6CheJrn/2q7j1kcy7iBltCsBJlKsJQ5bFQOy4x3PXObnJI PtMn2Z0xMZTg== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="271803148" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="271803148" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:34 -0800 IronPort-SDR: rHU0mce7zstuwz1Y1ABS5BsyShYeeUjL+9tn9noC+QPyO+ink+XTrg7VGXIqz2m1+3+v4451UZ neROB2MyF8HA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427472996" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:29 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 14/25] intel_iommu: sync IOMMU nesting cap info for assigned devices Date: Wed, 3 Mar 2021 04:38:16 +0800 Message-Id: <20210302203827.437645-15-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.43; envelope-from=yi.l.liu@intel.com; helo=mga05.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" For assigned devices, Intel vIOMMU which wants to build DMA protection based on physical IOMMU nesting paging should check the IOMMU nesting support in host side. The host will return IOMMU nesting cap info to user-space (e.g. VFIO returns IOMMU nesting cap info for nesting type IOMMU). vIOMMU needs to check: a) IOMMU model b) 1st-level page table supports c) address width d) pasid support This patch syncs the IOMMU nesting cap info when PCIe device (VFIO case) sets HostIOMMUContext to vIOMMU. If the host IOMMU nesting support is not compatible, vIOMMU should return failure to PCIe device. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Signed-off-by: Liu Yi L --- hw/i386/intel_iommu.c | 105 +++++++++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 18 ++++++ include/hw/i386/intel_iommu.h | 4 ++ 3 files changed, 127 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 8419fd2818..203c898fa4 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3494,6 +3494,82 @@ static int vtd_dev_get_iommu_attr(PCIBus *bus, void *opaque, int32_t devfn, return ret; } + +static bool vtd_check_nesting_info(IntelIOMMUState *s, + struct iommu_nesting_info *info, + struct iommu_nesting_info_vtd *vtd) +{ + return !((s->aw_bits != info->addr_width) || + ((s->host_cap ^ vtd->cap_reg) & VTD_CAP_MASK & s->host_cap) || + ((s->host_ecap ^ vtd->ecap_reg) & VTD_ECAP_MASK & s->host_ecap) || + (VTD_GET_PSS(s->host_ecap) != (info->pasid_bits - 1))); +} + +/* Caller should hold iommu lock. */ +static bool vtd_sync_nesting_info(IntelIOMMUState *s, + struct iommu_nesting_info *info) +{ + struct iommu_nesting_info_vtd *vtd; + uint64_t cap, ecap; + + vtd = (struct iommu_nesting_info_vtd *) &info->vendor.vtd; + + if (s->cap_finalized) { + return vtd_check_nesting_info(s, info, vtd); + } + + if (s->aw_bits > info->addr_width) { + error_report("User aw-bits: %u > host address width: %u", + s->aw_bits, info->addr_width); + return false; + } + + cap = s->host_cap & vtd->cap_reg & VTD_CAP_MASK; + s->host_cap &= ~VTD_CAP_MASK; + s->host_cap |= cap; + + ecap = s->host_ecap & vtd->ecap_reg & VTD_ECAP_MASK; + s->host_ecap &= ~VTD_ECAP_MASK; + s->host_ecap |= ecap; + + if ((VTD_ECAP_PASID & s->host_ecap) && info->pasid_bits && + (VTD_GET_PSS(s->host_ecap) > (info->pasid_bits - 1))) { + s->host_ecap &= ~VTD_ECAP_PSS_MASK; + s->host_ecap |= VTD_ECAP_PSS(info->pasid_bits - 1); + } + return true; +} + +/* + * virtual VT-d which wants nested needs to check the host IOMMU + * nesting cap info behind the assigned devices. Thus that vIOMMU + * could bind guest page table to host. + */ +static bool vtd_check_iommu_ctx(IntelIOMMUState *s, + HostIOMMUContext *iommu_ctx) +{ + struct iommu_nesting_info *info = iommu_ctx->info; + uint32_t minsz, size; + + if (IOMMU_PASID_FORMAT_INTEL_VTD != info->format) { + error_report("Format is not compatible for nesting!!!"); + return false; + } + + size = sizeof(struct iommu_nesting_info_vtd); + minsz = endof(struct iommu_nesting_info, flags); + if (size > (info->argsz - minsz)) { + /* + * QEMU may have been using new linux-headers/iommu.h than + * kernel supports, hence fail it. + */ + error_report("IOMMU nesting cap is not compatible!!!"); + return false; + } + + return vtd_sync_nesting_info(s, info); +} + static int vtd_dev_set_iommu_context(PCIBus *bus, void *opaque, int devfn, HostIOMMUContext *iommu_ctx) @@ -3508,6 +3584,11 @@ static int vtd_dev_set_iommu_context(PCIBus *bus, void *opaque, vtd_iommu_lock(s); + if (!vtd_check_iommu_ctx(s, iommu_ctx)) { + vtd_iommu_unlock(s); + return -ENOENT; + } + vtd_dev_icx = vtd_bus->dev_icx[devfn]; assert(!vtd_dev_icx); @@ -3760,6 +3841,14 @@ static void vtd_init(IntelIOMMUState *s) s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_SRS | VTD_ECAP_SLTS; } + if (!s->cap_finalized) { + s->host_cap = s->cap; + s->host_ecap = s->ecap; + } else { + s->cap = s->host_cap; + s->ecap = s->host_ecap; + } + vtd_reset_caches(s); /* Define registers with default values and bit semantics */ @@ -3886,6 +3975,12 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) return true; } +static void vtd_refresh_capability_reg(IntelIOMMUState *s) +{ + vtd_set_quad(s, DMAR_CAP_REG, s->cap); + vtd_set_quad(s, DMAR_ECAP_REG, s->ecap); +} + static int vtd_machine_done_notify_one(Object *child, void *unused) { IntelIOMMUState *iommu = INTEL_IOMMU_DEVICE(x86_iommu_get_default()); @@ -3899,6 +3994,15 @@ static int vtd_machine_done_notify_one(Object *child, void *unused) vtd_panic_require_caching_mode(); } + vtd_iommu_lock(iommu); + iommu->cap = iommu->host_cap & iommu->cap; + iommu->ecap = iommu->host_ecap & iommu->ecap; + if (!iommu->cap_finalized) { + iommu->cap_finalized = true; + } + + vtd_refresh_capability_reg(iommu); + vtd_iommu_unlock(iommu); return 0; } @@ -3929,6 +4033,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) QLIST_INIT(&s->vtd_as_with_notifiers); qemu_mutex_init(&s->iommu_lock); + s->cap_finalized = false; memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, "intel_iommu", DMAR_REG_SIZE); diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 445b45c948..af2c7bcd93 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -193,6 +193,24 @@ #define VTD_ECAP_SMTS (1ULL << 43) #define VTD_ECAP_SLTS (1ULL << 46) +/* 1st level related caps */ +#define VTD_CAP_FL1GP (1ULL << 56) +#define VTD_CAP_FL5LP (1ULL << 60) +#define VTD_ECAP_PRS (1ULL << 29) +#define VTD_ECAP_ERS (1ULL << 30) +#define VTD_ECAP_SRS (1ULL << 31) +#define VTD_ECAP_EAFS (1ULL << 34) +#define VTD_ECAP_PSS(val) (((val) & 0x1fULL) << 35) +#define VTD_ECAP_PASID (1ULL << 40) + +#define VTD_GET_PSS(val) (((val) >> 35) & 0x1f) +#define VTD_ECAP_PSS_MASK (0x1fULL << 35) + +#define VTD_CAP_MASK (VTD_CAP_FL1GP | VTD_CAP_FL5LP) +#define VTD_ECAP_MASK (VTD_ECAP_PRS | VTD_ECAP_ERS | \ + VTD_ECAP_SRS | VTD_ECAP_EAFS | \ + VTD_ECAP_PASID) + /* CAP_REG */ /* (offset >> 4) << 24 */ #define VTD_CAP_FRO (DMAR_FRCD_REG_OFFSET << 20) diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 28396675ef..d6a90f07f4 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -260,6 +260,9 @@ struct IntelIOMMUState { uint64_t cap; /* The value of capability reg */ uint64_t ecap; /* The value of extended capability reg */ + uint64_t host_cap; /* The value of host capability reg */ + uint64_t host_ecap; /* The value of host ext-capability reg */ + uint32_t context_cache_gen; /* Should be in [1,MAX] */ GHashTable *iotlb; /* IOTLB */ @@ -278,6 +281,7 @@ struct IntelIOMMUState { uint8_t aw_bits; /* Host/IOVA address width (in bits) */ bool dma_drain; /* Whether DMA r/w draining enabled */ + bool cap_finalized; /* Whether VTD capability finalized */ /* * iommu_lock protects below: * - per-IOMMU IOTLB caches From patchwork Tue Mar 2 20:38:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446032 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcfN1dP3z9sS8 for ; Tue, 2 Mar 2021 23:59:40 +1100 (AEDT) Received: from localhost ([::1]:58172 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4ck-0004A6-9B for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:59:38 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33122) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KR-00080E-MR for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:43 -0500 Received: from mga05.intel.com ([192.55.52.43]:62468) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KN-0002nT-Rd for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:43 -0500 IronPort-SDR: iqAcw1ZWA/c5epOyOhUIi8QeBSSYhwn47GZIxeCuIlNiKpSYFsknsW+8xYaDGnJv1j/pjXsvLd 3SD/ofR15+7Q== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="271803162" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="271803162" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:39 -0800 IronPort-SDR: O6wXUzhQlrXAXH4LJDAxQ03MeYn/fgXrDaex8JJdX3qOav0lwfTquG6+24W9T2udw/HsqB5DfX v3lYO6H6gQuA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473011" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:34 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 15/25] intel_iommu: add virtual command capability support Date: Wed, 3 Mar 2021 04:38:17 +0800 Message-Id: <20210302203827.437645-16-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.43; envelope-from=yi.l.liu@intel.com; helo=mga05.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds virtual command support to Intel vIOMMU per Intel VT-d 3.1 spec. And adds two virtual commands: allocate pasid and free pasid. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Reviewed-by: Peter Xu Signed-off-by: Liu Yi L Signed-off-by: Yi Sun --- rfcv10 -> rfcv11: *) use /dev/ioasid FD for pasid alloc/free, /dev/ioasid open is added in latter patch. --- hw/i386/intel_iommu.c | 141 +++++++++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 37 +++++++++ hw/i386/trace-events | 1 + include/hw/i386/intel_iommu.h | 10 ++- 4 files changed, 188 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 203c898fa4..7786f97ed6 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -40,6 +40,11 @@ #include "kvm/kvm_i386.h" #include "migration/vmstate.h" #include "trace.h" +#include +#include + +int ioasid_fd = -1; +uint32_t ioasid_bits; /* context entry operations */ #define VTD_CE_GET_RID2PASID(ce) \ @@ -2678,6 +2683,118 @@ static void vtd_handle_iectl_write(IntelIOMMUState *s) } } +static int vtd_request_pasid_alloc(IntelIOMMUState *s, uint32_t *pasid) +{ + struct ioasid_alloc_request req; + int ret; + + req.argsz = sizeof(req); + req.flags = 0; + req.range.min = VTD_HPASID_MIN; + req.range.max = VTD_HPASID_MAX; + + if (s->ioasid_fd < 0) { + error_report("%s: No available allocation interface", __func__); + return -1; + } + + vtd_iommu_lock(s); + ret = ioctl(s->ioasid_fd, IOASID_REQUEST_ALLOC, &req); + if (ret < 0) { + error_report("%s: alloc failed %d", __func__, ret); + } + printf("%s, ret: %d\n", __func__, ret); + vtd_iommu_unlock(s); + *pasid = ret; + return (ret < 0) ? ret : 0; +} + +static int vtd_request_pasid_free(IntelIOMMUState *s, uint32_t pasid) +{ + int ret = -1; + + if (s->ioasid_fd < 0) { + error_report("%s: No available allocation interface", __func__); + return -1; + } + + vtd_iommu_lock(s); + ret = ioctl(s->ioasid_fd, IOASID_REQUEST_FREE, &pasid); + if (ret < 0) { + error_report("%s: free failed (%m)", __func__); + } + vtd_iommu_unlock(s); + + return ret; +} + +/* + * If IP is not set, set it then return. + * If IP is already set, return. + */ +static void vtd_vcmd_set_ip(IntelIOMMUState *s) +{ + s->vcrsp = 1; + vtd_set_quad_raw(s, DMAR_VCRSP_REG, + ((uint64_t) s->vcrsp)); +} + +static void vtd_vcmd_clear_ip(IntelIOMMUState *s) +{ + s->vcrsp &= (~((uint64_t)(0x1))); + vtd_set_quad_raw(s, DMAR_VCRSP_REG, + ((uint64_t) s->vcrsp)); +} + +/* Handle write to Virtual Command Register */ +static int vtd_handle_vcmd_write(IntelIOMMUState *s, uint64_t val) +{ + uint32_t pasid; + int ret = -1; + + trace_vtd_reg_write_vcmd(s->vcrsp, val); + + if (!(s->vccap & VTD_VCCAP_PAS) || + (s->vcrsp & 1)) { + return -1; + } + + /* + * Since vCPU should be blocked when the guest VMCD + * write was trapped to here. Should be no other vCPUs + * try to access VCMD if guest software is well written. + * However, we still emulate the IP bit here in case of + * bad guest software. Also align with the spec. + */ + vtd_vcmd_set_ip(s); + + switch (val & VTD_VCMD_CMD_MASK) { + case VTD_VCMD_ALLOC_PASID: + ret = vtd_request_pasid_alloc(s, &pasid); + if (ret) { + s->vcrsp |= VTD_VCRSP_SC(VTD_VCMD_NO_AVAILABLE_PASID); + } else { + s->vcrsp |= VTD_VCRSP_RSLT(pasid); + } + break; + + case VTD_VCMD_FREE_PASID: + pasid = VTD_VCMD_PASID_VALUE(val); + ret = vtd_request_pasid_free(s, pasid); + if (ret < 0) { + s->vcrsp |= VTD_VCRSP_SC(VTD_VCMD_FREE_INVALID_PASID); + } + break; + + default: + s->vcrsp |= VTD_VCRSP_SC(VTD_VCMD_UNDEFINED_CMD); + error_report_once("Virtual Command: unsupported command!!!"); + break; + } + vtd_vcmd_clear_ip(s); + return 0; +} + static uint64_t vtd_mem_read(void *opaque, hwaddr addr, unsigned size) { IntelIOMMUState *s = opaque; @@ -2966,6 +3083,23 @@ static void vtd_mem_write(void *opaque, hwaddr addr, vtd_set_long(s, addr, val); break; + case DMAR_VCMD_REG: + if (!vtd_handle_vcmd_write(s, val)) { + if (size == 4) { + vtd_set_long(s, addr, val); + } else { + vtd_set_quad(s, addr, val); + } + } + break; + + case DMAR_VCMD_REG_HI: + assert(size == 4); + if (!vtd_handle_vcmd_write(s, val)) { + vtd_set_long(s, addr, val); + } + break; + default: if (size == 4) { vtd_set_long(s, addr, val); @@ -3902,6 +4036,13 @@ static void vtd_init(IntelIOMMUState *s) * Interrupt remapping registers. */ vtd_define_quad(s, DMAR_IRTA_REG, 0, 0xfffffffffffff80fULL, 0); + + /* + * Virtual Command Definitions + */ + vtd_define_quad(s, DMAR_VCCAP_REG, s->vccap, 0, 0); + vtd_define_quad(s, DMAR_VCMD_REG, 0, 0xffffffffffffffffULL, 0); + vtd_define_quad(s, DMAR_VCRSP_REG, 0, 0, 0); } /* Should not reset address_spaces when reset because devices will still use diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index af2c7bcd93..6abb4836a1 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -85,6 +85,12 @@ #define DMAR_MTRRCAP_REG_HI 0x104 #define DMAR_MTRRDEF_REG 0x108 /* MTRR default type */ #define DMAR_MTRRDEF_REG_HI 0x10c +#define DMAR_VCCAP_REG 0xE00 /* Virtual Command Capability Register */ +#define DMAR_VCCAP_REG_HI 0xE04 +#define DMAR_VCMD_REG 0xE10 /* Virtual Command Register */ +#define DMAR_VCMD_REG_HI 0xE14 +#define DMAR_VCRSP_REG 0xE20 /* Virtual Command Reponse Register */ +#define DMAR_VCRSP_REG_HI 0xE24 /* IOTLB registers */ #define DMAR_IOTLB_REG_OFFSET 0xf0 /* Offset to the IOTLB registers */ @@ -331,6 +337,37 @@ typedef enum VTDFaultReason { #define VTD_CONTEXT_CACHE_GEN_MAX 0xffffffffUL +/* VCCAP_REG */ +#define VTD_VCCAP_PAS (1UL << 0) + +/* + * The basic idea is to let hypervisor to set a range for available + * PASIDs for VMs. One of the reasons is PASID #0 is reserved by + * RID_PASID usage. We have no idea how many reserved PASIDs in future, + * so here just an evaluated value. Honestly, set it as "1" is enough + * at current stage. + */ +#define VTD_HPASID_MIN 1 +#define VTD_HPASID_MAX 0xFFFFF + +/* Virtual Command Register */ +enum { + VTD_VCMD_NULL_CMD = 0, + VTD_VCMD_ALLOC_PASID = 1, + VTD_VCMD_FREE_PASID = 2, + VTD_VCMD_CMD_NUM, +}; + +#define VTD_VCMD_CMD_MASK 0xffUL +#define VTD_VCMD_PASID_VALUE(val) (((val) >> 8) & 0xfffff) + +#define VTD_VCRSP_RSLT(val) ((val) << 8) +#define VTD_VCRSP_SC(val) (((val) & 0x3) << 1) + +#define VTD_VCMD_UNDEFINED_CMD 1ULL +#define VTD_VCMD_NO_AVAILABLE_PASID 2ULL +#define VTD_VCMD_FREE_INVALID_PASID 2ULL + /* Interrupt Entry Cache Invalidation Descriptor: VT-d 6.5.2.7. */ struct VTDInvDescIEC { uint32_t type:4; /* Should always be 0x4 */ diff --git a/hw/i386/trace-events b/hw/i386/trace-events index e48bef2b0d..71536a7c20 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -51,6 +51,7 @@ vtd_reg_write_gcmd(uint32_t status, uint32_t val) "status 0x%"PRIx32" value 0x%" vtd_reg_write_fectl(uint32_t value) "value 0x%"PRIx32 vtd_reg_write_iectl(uint32_t value) "value 0x%"PRIx32 vtd_reg_ics_clear_ip(void) "" +vtd_reg_write_vcmd(uint32_t status, uint32_t val) "status 0x%"PRIx32" value 0x%"PRIx32 vtd_dmar_translate(uint8_t bus, uint8_t slot, uint8_t func, uint64_t iova, uint64_t gpa, uint64_t mask) "dev %02x:%02x.%02x iova 0x%"PRIx64" -> gpa 0x%"PRIx64" mask 0x%"PRIx64 vtd_dmar_enable(bool en) "enable %d" vtd_dmar_fault(uint16_t sid, int fault, uint64_t addr, bool is_write) "sid 0x%"PRIx16" fault %d addr 0x%"PRIx64" write %d" diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index d6a90f07f4..cca9c821fe 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -42,7 +42,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(IntelIOMMUState, INTEL_IOMMU_DEVICE) #define VTD_SID_TO_BUS(sid) (((sid) >> 8) & 0xff) #define VTD_SID_TO_DEVFN(sid) ((sid) & 0xff) -#define DMAR_REG_SIZE 0x230 +#define DMAR_REG_SIZE 0xF00 #define VTD_HOST_AW_39BIT 39 #define VTD_HOST_AW_48BIT 48 #define VTD_HOST_ADDRESS_WIDTH VTD_HOST_AW_39BIT @@ -281,6 +281,14 @@ struct IntelIOMMUState { uint8_t aw_bits; /* Host/IOVA address width (in bits) */ bool dma_drain; /* Whether DMA r/w draining enabled */ + /* Virtual Command Register */ + uint64_t vccap; /* The value of vcmd capability reg */ + uint64_t vcrsp; /* Current value of VCMD RSP REG */ + /* /dev/ioasid interface */ + int ioasid_fd; /* /dev/ioasid FD */ + uint32_t ioasid_bits; /* IOASID width supported by + host (in bits) */ + bool cap_finalized; /* Whether VTD capability finalized */ /* * iommu_lock protects below: From patchwork Tue Mar 2 20:38:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446033 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Dqcjz22ngz9sS8 for ; Wed, 3 Mar 2021 00:02:44 +1100 (AEDT) Received: from localhost ([::1]:32944 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4fh-0005pu-Bm for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 08:02:41 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33178) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KX-00087S-F4 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:49 -0500 Received: from mga05.intel.com ([192.55.52.43]:62468) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KT-0002nT-Hj for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:49 -0500 IronPort-SDR: dtVjjxp30Cqx7gaRvjNHDLVonhuQOYmI1fmDI9L2ykF/eDKsXdp4dX8qAmLw5jiBAwzmNBDYyN jllJ5FnIKtJw== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="271803191" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="271803191" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:43 -0800 IronPort-SDR: e9oayeS8me02jaknIuo/+Jgr5LFf0gWaxiL2QqfyJiGbS4GD0Wlhfco3vfFmXgmXMJM6Yekikw u5OWYO1AGJTA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473029" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:39 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 16/25] intel_iommu: process PASID cache invalidation Date: Wed, 3 Mar 2021 04:38:18 +0800 Message-Id: <20210302203827.437645-17-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.43; envelope-from=yi.l.liu@intel.com; helo=mga05.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds PASID cache invalidation handling. When guest enabled PASID usages (e.g. SVA), guest software should issue a proper PASID cache invalidation when caching-mode is exposed. This patch only adds the draft handling of pasid cache invalidation. Detailed handling will be added in subsequent patches. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Reviewed-by: Peter Xu Signed-off-by: Liu Yi L --- rfcv4 (v1) -> rfcv5 (v2): *) remove vtd_pasid_cache_gsi(), vtd_pasid_cache_psi() and vtd_pasid_cache_dsi() --- hw/i386/intel_iommu.c | 40 +++++++++++++++++++++++++++++----- hw/i386/intel_iommu_internal.h | 12 ++++++++++ hw/i386/trace-events | 3 +++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 7786f97ed6..c4b0db15cb 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2421,6 +2421,37 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) return true; } +static bool vtd_process_pasid_desc(IntelIOMMUState *s, + VTDInvDesc *inv_desc) +{ + if ((inv_desc->val[0] & VTD_INV_DESC_PASIDC_RSVD_VAL0) || + (inv_desc->val[1] & VTD_INV_DESC_PASIDC_RSVD_VAL1) || + (inv_desc->val[2] & VTD_INV_DESC_PASIDC_RSVD_VAL2) || + (inv_desc->val[3] & VTD_INV_DESC_PASIDC_RSVD_VAL3)) { + error_report_once("non-zero-field-in-pc_inv_desc hi: 0x%" PRIx64 + " lo: 0x%" PRIx64, inv_desc->val[1], inv_desc->val[0]); + return false; + } + + switch (inv_desc->val[0] & VTD_INV_DESC_PASIDC_G) { + case VTD_INV_DESC_PASIDC_DSI: + break; + + case VTD_INV_DESC_PASIDC_PASID_SI: + break; + + case VTD_INV_DESC_PASIDC_GLOBAL: + break; + + default: + error_report_once("invalid-inv-granu-in-pc_inv_desc hi: 0x%" PRIx64 + " lo: 0x%" PRIx64, inv_desc->val[1], inv_desc->val[0]); + return false; + } + + return true; +} + static bool vtd_process_inv_iec_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { @@ -2528,12 +2559,11 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) } break; - /* - * TODO: the entity of below two cases will be implemented in future series. - * To make guest (which integrates scalable mode support patch set in - * iommu driver) work, just return true is enough so far. - */ case VTD_INV_DESC_PC: + trace_vtd_inv_desc("pasid-cache", inv_desc.val[1], inv_desc.val[0]); + if (!vtd_process_pasid_desc(s, &inv_desc)) { + return false; + } break; case VTD_INV_DESC_PIOTLB: diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 6abb4836a1..3c8853ab88 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -463,6 +463,18 @@ typedef union VTDInvDesc VTDInvDesc; (0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \ (0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM)) +#define VTD_INV_DESC_PASIDC_G (3ULL << 4) +#define VTD_INV_DESC_PASIDC_PASID(val) (((val) >> 32) & 0xfffffULL) +#define VTD_INV_DESC_PASIDC_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK) +#define VTD_INV_DESC_PASIDC_RSVD_VAL0 0xfff000000000ffc0ULL +#define VTD_INV_DESC_PASIDC_RSVD_VAL1 0xffffffffffffffffULL +#define VTD_INV_DESC_PASIDC_RSVD_VAL2 0xffffffffffffffffULL +#define VTD_INV_DESC_PASIDC_RSVD_VAL3 0xffffffffffffffffULL + +#define VTD_INV_DESC_PASIDC_DSI (0ULL << 4) +#define VTD_INV_DESC_PASIDC_PASID_SI (1ULL << 4) +#define VTD_INV_DESC_PASIDC_GLOBAL (3ULL << 4) + /* Information about page-selective IOTLB invalidate */ struct VTDIOTLBPageInvInfo { uint16_t domain_id; diff --git a/hw/i386/trace-events b/hw/i386/trace-events index 71536a7c20..f7cd4e5656 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -22,6 +22,9 @@ vtd_inv_qi_head(uint16_t head) "read head %d" vtd_inv_qi_tail(uint16_t head) "write tail %d" vtd_inv_qi_fetch(void) "" vtd_context_cache_reset(void) "" +vtd_pasid_cache_gsi(void) "" +vtd_pasid_cache_dsi(uint16_t domain) "Domian slective PC invalidation domain 0x%"PRIx16 +vtd_pasid_cache_psi(uint16_t domain, uint32_t pasid) "PASID slective PC invalidation domain 0x%"PRIx16" pasid 0x%"PRIx32 vtd_re_not_present(uint8_t bus) "Root entry bus %"PRIu8" not present" vtd_ce_not_present(uint8_t bus, uint8_t devfn) "Context entry bus %"PRIu8" devfn %"PRIu8" not present" vtd_iotlb_page_hit(uint16_t sid, uint64_t addr, uint64_t slpte, uint16_t domain) "IOTLB page hit sid 0x%"PRIx16" iova 0x%"PRIx64" slpte 0x%"PRIx64" domain 0x%"PRIx16 From patchwork Tue Mar 2 20:38:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446018 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcPK3SSMz9sVw for ; Tue, 2 Mar 2021 23:48:21 +1100 (AEDT) Received: from localhost ([::1]:53904 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4Rn-0006uo-Dc for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:48:19 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33206) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Kd-0008Ey-E2 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:56 -0500 Received: from mga12.intel.com ([192.55.52.136]:6961) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4KY-0002rx-Ne for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:55 -0500 IronPort-SDR: XLTH8bb7MYIp5Zba/MU9x2h97kvHzyNNckTqPdNIzxEGRWCp2bP6VS9zRtYwjd5iNZ1awAQOj/ 5u0xxx+VHA5g== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="166033876" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="166033876" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:49 -0800 IronPort-SDR: YMF6mpIlNFelvFj9qwelqYAFT80KDDZil56cgvJbYRKyKTpJiqsr+OGdMT3TdZWo0Qz3eNgcsU uEz8R7RyR2AQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473043" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:44 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 17/25] intel_iommu: add PASID cache management infrastructure Date: Wed, 3 Mar 2021 04:38:19 +0800 Message-Id: <20210302203827.437645-18-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.136; envelope-from=yi.l.liu@intel.com; helo=mga12.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds a PASID cache management infrastructure based on new added structure VTDPASIDAddressSpace, which is used to track the PASID usage and future PASID tagged DMA address translation support in vIOMMU. struct VTDPASIDAddressSpace { VTDBus *vtd_bus; uint8_t devfn; AddressSpace as; uint32_t pasid; IntelIOMMUState *iommu_state; VTDContextCacheEntry context_cache_entry; QLIST_ENTRY(VTDPASIDAddressSpace) next; VTDPASIDCacheEntry pasid_cache_entry; }; Ideally, a VTDPASIDAddressSpace instance is created when a PASID is bound with a DMA AddressSpace. Intel VT-d spec requires guest software to issue pasid cache invalidation when bind or unbind a pasid with an address space under caching-mode. However, as VTDPASIDAddressSpace instances also act as pasid cache in this implementation, its creation also happens during vIOMMU PASID tagged DMA translation. The creation in this path will not be added in this patch since no PASID-capable emulated devices for now. The implementation in this patch manages VTDPASIDAddressSpace instances per PASID+BDF (lookup and insert will use PASID and BDF) since Intel VT-d spec allows per-BDF PASID Table. When a guest bind a PASID with an AddressSpace, QEMU will capture the guest pasid selective pasid cache invalidation, and allocate remove a VTDPASIDAddressSpace instance per the invalidation reasons: *) a present pasid entry moved to non-present *) a present pasid entry to be a present entry *) a non-present pasid entry moved to present vIOMMU emulator could figure out the reason by fetching latest guest pasid entry. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Liu Yi L --- rfcv4 (v1) -> rfcv5 (v2): *) merged this patch with former replay binding patch, makes PSI/DSI/GSI use the unified function to do cache invalidation and pasid binding replay. *) dropped pasid_cache_gen in both iommu_state and vtd_pasid_as as it is not necessary so far, we may want it when one day initroduce emulated SVA-capable device. --- hw/i386/intel_iommu.c | 471 ++++++++++++++++++++++++++++++++- hw/i386/intel_iommu_internal.h | 21 ++ hw/i386/trace-events | 1 + include/hw/i386/intel_iommu.h | 28 ++ 4 files changed, 520 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index c4b0db15cb..a8f895807a 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -42,6 +42,7 @@ #include "trace.h" #include #include +#include "qemu/jhash.h" int ioasid_fd = -1; uint32_t ioasid_bits; @@ -70,6 +71,8 @@ uint32_t ioasid_bits; static void vtd_address_space_refresh_all(IntelIOMMUState *s); static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n); +static void vtd_pasid_cache_reset(IntelIOMMUState *s); + static void vtd_panic_require_caching_mode(void) { error_report("We need to set caching-mode=on for intel-iommu to enable " @@ -281,6 +284,7 @@ static void vtd_reset_caches(IntelIOMMUState *s) vtd_iommu_lock(s); vtd_reset_iotlb_locked(s); vtd_reset_context_cache_locked(s); + vtd_pasid_cache_reset(s); vtd_iommu_unlock(s); } @@ -691,6 +695,16 @@ static inline bool vtd_pe_type_check(X86IOMMUState *x86_iommu, return true; } +static inline uint16_t vtd_pe_get_domain_id(VTDPASIDEntry *pe) +{ + return VTD_SM_PASID_ENTRY_DID((pe)->val[1]); +} + +static inline uint32_t vtd_sm_ce_get_pdt_entry_num(VTDContextEntry *ce) +{ + return 1U << (VTD_SM_CONTEXT_ENTRY_PDTS(ce->val[0]) + 7); +} + static inline bool vtd_pdire_present(VTDPASIDDirEntry *pdire) { return pdire->val & 1; @@ -2421,9 +2435,443 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) return true; } +static inline void vtd_init_pasid_key(uint32_t pasid, + uint16_t sid, + struct pasid_key *key) +{ + key->pasid = pasid; + key->sid = sid; +} + +static guint vtd_pasid_as_key_hash(gconstpointer v) +{ + struct pasid_key *key = (struct pasid_key *)v; + uint32_t a, b, c; + + /* Jenkins hash */ + a = b = c = JHASH_INITVAL + sizeof(*key); + a += key->sid; + b += extract32(key->pasid, 0, 16); + c += extract32(key->pasid, 16, 16); + + __jhash_mix(a, b, c); + __jhash_final(a, b, c); + + return c; +} + +static gboolean vtd_pasid_as_key_equal(gconstpointer v1, gconstpointer v2) +{ + const struct pasid_key *k1 = v1; + const struct pasid_key *k2 = v2; + + return (k1->pasid == k2->pasid) && (k1->sid == k2->sid); +} + +static inline int vtd_dev_get_pe_from_pasid(IntelIOMMUState *s, + uint8_t bus_num, + uint8_t devfn, + uint32_t pasid, + VTDPASIDEntry *pe) +{ + VTDContextEntry ce; + int ret; + dma_addr_t pasid_dir_base; + + if (!s->root_scalable) { + return -VTD_FR_PASID_TABLE_INV; + } + + ret = vtd_dev_to_context_entry(s, bus_num, devfn, &ce); + if (ret) { + return ret; + } + + pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(&ce); + ret = vtd_get_pe_from_pasid_table(s, + pasid_dir_base, pasid, pe); + + return ret; +} + +static bool vtd_pasid_entry_compare(VTDPASIDEntry *p1, VTDPASIDEntry *p2) +{ + return !memcmp(p1, p2, sizeof(*p1)); +} + +/** + * This function fills in the pasid entry in &vtd_pasid_as. Caller + * of this function should hold iommu_lock. + */ +static void vtd_fill_pe_in_cache(IntelIOMMUState *s, + VTDPASIDAddressSpace *vtd_pasid_as, + VTDPASIDEntry *pe) +{ + VTDPASIDCacheEntry *pc_entry = &vtd_pasid_as->pasid_cache_entry; + + if (vtd_pasid_entry_compare(pe, &pc_entry->pasid_entry)) { + /* No need to go further as cached pasid entry is latest */ + return; + } + + pc_entry->pasid_entry = *pe; + /* + * TODO: + * - send pasid bind to host for passthru devices + */ +} + +/** + * This function is used to clear cached pasid entry in vtd_pasid_as + * instances. Caller of this function should hold iommu_lock. + */ +static gboolean vtd_flush_pasid(gpointer key, gpointer value, + gpointer user_data) +{ + VTDPASIDCacheInfo *pc_info = user_data; + VTDPASIDAddressSpace *vtd_pasid_as = value; + IntelIOMMUState *s = vtd_pasid_as->iommu_state; + VTDPASIDCacheEntry *pc_entry = &vtd_pasid_as->pasid_cache_entry; + VTDBus *vtd_bus = vtd_pasid_as->vtd_bus; + VTDPASIDEntry pe; + uint16_t did; + uint32_t pasid; + uint16_t devfn; + int ret; + + did = vtd_pe_get_domain_id(&pc_entry->pasid_entry); + pasid = vtd_pasid_as->pasid; + devfn = vtd_pasid_as->devfn; + + switch (pc_info->type) { + case VTD_PASID_CACHE_FORCE_RESET: + goto remove; + case VTD_PASID_CACHE_PASIDSI: + if (pc_info->pasid != pasid) { + return false; + } + /* Fall through */ + case VTD_PASID_CACHE_DOMSI: + if (pc_info->domain_id != did) { + return false; + } + /* Fall through */ + case VTD_PASID_CACHE_GLOBAL_INV: + break; + default: + error_report("invalid pc_info->type"); + abort(); + } + + /* + * pasid cache invalidation may indicate a present pasid + * entry to present pasid entry modification. To cover such + * case, vIOMMU emulator needs to fetch latest guest pasid + * entry and check cached pasid entry, then update pasid + * cache and send pasid bind/unbind to host properly. + */ + ret = vtd_dev_get_pe_from_pasid(s, pci_bus_num(vtd_bus->bus), + devfn, pasid, &pe); + if (ret) { + /* + * No valid pasid entry in guest memory. e.g. pasid entry + * was modified to be either all-zero or non-present. Either + * case means existing pasid cache should be removed. + */ + goto remove; + } + + vtd_fill_pe_in_cache(s, vtd_pasid_as, &pe); + /* + * TODO: + * - when pasid-base-iotlb(piotlb) infrastructure is ready, + * should invalidate QEMU piotlb togehter with this change. + */ + return false; +remove: + /* + * TODO: + * - send pasid bind to host for passthru devices + * - when pasid-base-iotlb(piotlb) infrastructure is ready, + * should invalidate QEMU piotlb togehter with this change. + */ + return true; +} + +/** + * This function finds or adds a VTDPASIDAddressSpace for a device + * when it is bound to a pasid. Caller of this function should hold + * iommu_lock. + */ +static VTDPASIDAddressSpace *vtd_add_find_pasid_as(IntelIOMMUState *s, + VTDBus *vtd_bus, + int devfn, + uint32_t pasid) +{ + struct pasid_key key; + struct pasid_key *new_key; + VTDPASIDAddressSpace *vtd_pasid_as; + uint16_t sid; + + sid = vtd_make_source_id(pci_bus_num(vtd_bus->bus), devfn); + vtd_init_pasid_key(pasid, sid, &key); + vtd_pasid_as = g_hash_table_lookup(s->vtd_pasid_as, &key); + + if (!vtd_pasid_as) { + new_key = g_malloc0(sizeof(*new_key)); + vtd_init_pasid_key(pasid, sid, new_key); + /* + * Initiate the vtd_pasid_as structure. + * + * This structure here is used to track the guest pasid + * binding and also serves as pasid-cache mangement entry. + * + * TODO: in future, if wants to support the SVA-aware DMA + * emulation, the vtd_pasid_as should have include + * AddressSpace to support DMA emulation. + */ + vtd_pasid_as = g_malloc0(sizeof(VTDPASIDAddressSpace)); + vtd_pasid_as->iommu_state = s; + vtd_pasid_as->vtd_bus = vtd_bus; + vtd_pasid_as->devfn = devfn; + vtd_pasid_as->pasid = pasid; + g_hash_table_insert(s->vtd_pasid_as, new_key, vtd_pasid_as); + } + return vtd_pasid_as; +} + +/** + * Caller of this function should hold iommu_lock. + */ +static void vtd_sm_pasid_table_walk_one(IntelIOMMUState *s, + dma_addr_t pt_base, + int start, + int end, + VTDPASIDCacheInfo *info) +{ + VTDPASIDEntry pe; + int pasid = start; + int pasid_next; + VTDPASIDAddressSpace *vtd_pasid_as; + + while (pasid < end) { + pasid_next = pasid + 1; + + if (!vtd_get_pe_in_pasid_leaf_table(s, pasid, pt_base, &pe) + && vtd_pe_present(&pe)) { + vtd_pasid_as = vtd_add_find_pasid_as(s, + info->vtd_bus, info->devfn, pasid); + if ((info->type == VTD_PASID_CACHE_DOMSI || + info->type == VTD_PASID_CACHE_PASIDSI) && + !(info->domain_id == vtd_pe_get_domain_id(&pe))) { + /* + * VTD_PASID_CACHE_DOMSI and VTD_PASID_CACHE_PASIDSI + * requires domain ID check. If domain Id check fail, + * go to next pasid. + */ + pasid = pasid_next; + continue; + } + vtd_fill_pe_in_cache(s, vtd_pasid_as, &pe); + } + pasid = pasid_next; + } +} + +/* + * Currently, VT-d scalable mode pasid table is a two level table, + * this function aims to loop a range of PASIDs in a given pasid + * table to identify the pasid config in guest. + * Caller of this function should hold iommu_lock. + */ +static void vtd_sm_pasid_table_walk(IntelIOMMUState *s, + dma_addr_t pdt_base, + int start, + int end, + VTDPASIDCacheInfo *info) +{ + VTDPASIDDirEntry pdire; + int pasid = start; + int pasid_next; + dma_addr_t pt_base; + + while (pasid < end) { + pasid_next = ((end - pasid) > VTD_PASID_TBL_ENTRY_NUM) ? + (pasid + VTD_PASID_TBL_ENTRY_NUM) : end; + if (!vtd_get_pdire_from_pdir_table(pdt_base, pasid, &pdire) + && vtd_pdire_present(&pdire)) { + pt_base = pdire.val & VTD_PASID_TABLE_BASE_ADDR_MASK; + vtd_sm_pasid_table_walk_one(s, pt_base, pasid, pasid_next, info); + } + pasid = pasid_next; + } +} + +static void vtd_replay_pasid_bind_for_dev(IntelIOMMUState *s, + int start, int end, + VTDPASIDCacheInfo *info) +{ + VTDContextEntry ce; + int bus_n, devfn; + + bus_n = pci_bus_num(info->vtd_bus->bus); + devfn = info->devfn; + + if (!vtd_dev_to_context_entry(s, bus_n, devfn, &ce)) { + uint32_t max_pasid; + + max_pasid = vtd_sm_ce_get_pdt_entry_num(&ce) * VTD_PASID_TBL_ENTRY_NUM; + if (end > max_pasid) { + end = max_pasid; + } + vtd_sm_pasid_table_walk(s, + VTD_CE_GET_PASID_DIR_TABLE(&ce), + start, + end, + info); + } +} + +/** + * This function replay the guest pasid bindings to hots by + * walking the guest PASID table. This ensures host will have + * latest guest pasid bindings. Caller should hold iommu_lock. + */ +static void vtd_replay_guest_pasid_bindings(IntelIOMMUState *s, + VTDPASIDCacheInfo *pc_info) +{ + VTDHostIOMMUContext *vtd_dev_icx; + int start = 0, end = VTD_HPASID_MAX; + VTDPASIDCacheInfo walk_info; + + switch (pc_info->type) { + case VTD_PASID_CACHE_PASIDSI: + start = pc_info->pasid; + end = pc_info->pasid + 1; + /* + * PASID selective invalidation is within domain, + * thus fall through. + */ + case VTD_PASID_CACHE_DOMSI: + case VTD_PASID_CACHE_GLOBAL_INV: + /* loop all assigned devices */ + break; + case VTD_PASID_CACHE_FORCE_RESET: + /* For force reset, no need to go further replay */ + return; + default: + error_report("invalid pc_info->type for replay"); + abort(); + } + + /* + * In this replay, only needs to care about the devices which + * are backed by host IOMMU. For such devices, their vtd_dev_icx + * instances are in the s->vtd_dev_icx_list. For devices which + * are not backed byhost IOMMU, it is not necessary to replay + * the bindings since their cache could be re-created in the future + * DMA address transaltion. + */ + walk_info = *pc_info; + QLIST_FOREACH(vtd_dev_icx, &s->vtd_dev_icx_list, next) { + /* vtd_bus|devfn fields are not identical with pc_info */ + walk_info.vtd_bus = vtd_dev_icx->vtd_bus; + walk_info.devfn = vtd_dev_icx->devfn; + vtd_replay_pasid_bind_for_dev(s, start, end, &walk_info); + } +} + +/** + * This function syncs the pasid bindings between guest and host. + * It includes updating the pasid cache in vIOMMU and updating the + * pasid bindings per guest's latest pasid entry presence. + */ +static void vtd_pasid_cache_sync(IntelIOMMUState *s, + VTDPASIDCacheInfo *pc_info) +{ + /* + * Regards to a pasid cache invalidation, e.g. a PSI. + * it could be either cases of below: + * a) a present pasid entry moved to non-present + * b) a present pasid entry to be a present entry + * c) a non-present pasid entry moved to present + * + * Different invalidation granularity may affect different device + * scope and pasid scope. But for each invalidation granularity, + * it needs to do two steps to sync host and guest pasid binding. + * + * Here is the handling of a PSI: + * 1) loop all the existing vtd_pasid_as instances to update them + * according to the latest guest pasid entry in pasid table. + * this will make sure affected existing vtd_pasid_as instances + * cached the latest pasid entries. Also, during the loop, the + * host should be notified if needed. e.g. pasid unbind or pasid + * update. Should be able to cover case a) and case b). + * + * 2) loop all devices to cover case c) + * - For devices which have HostIOMMUContext instances, + * we loop them and check if guest pasid entry exists. If yes, + * it is case c), we update the pasid cache and also notify + * host. + * - For devices which have no HostIOMMUContext, it is not + * necessary to create pasid cache at this phase since it + * could be created when vIOMMU does DMA address translation. + * This is not yet implemented since there is no emulated + * pasid-capable devices today. If we have such devices in + * future, the pasid cache shall be created there. + * Other granularity follow the same steps, just with different scope + * + */ + + vtd_iommu_lock(s); + /* Step 1: loop all the exisitng vtd_pasid_as instances */ + g_hash_table_foreach_remove(s->vtd_pasid_as, + vtd_flush_pasid, pc_info); + + /* + * Step 2: loop all the exisitng vtd_dev_icx instances. + * Ideally, needs to loop all devices to find if there is any new + * PASID binding regards to the PASID cache invalidation request. + * But it is enough to loop the devices which are backed by host + * IOMMU. For devices backed by vIOMMU (a.k.a emulated devices), + * if new PASID happened on them, their vtd_pasid_as instance could + * be created during future vIOMMU DMA translation. + */ + vtd_replay_guest_pasid_bindings(s, pc_info); + vtd_iommu_unlock(s); +} + +/** + * Caller of this function should hold iommu_lock + */ +static void vtd_pasid_cache_reset(IntelIOMMUState *s) +{ + VTDPASIDCacheInfo pc_info; + + trace_vtd_pasid_cache_reset(); + + pc_info.type = VTD_PASID_CACHE_FORCE_RESET; + + /* + * Reset pasid cache is a big hammer, so use + * g_hash_table_foreach_remove which will free + * the vtd_pasid_as instances. Also, as a big + * hammer, use VTD_PASID_CACHE_FORCE_RESET to + * ensure all the vtd_pasid_as instances are + * dropped, meanwhile the change will be pass + * to host if HostIOMMUContext is available. + */ + g_hash_table_foreach_remove(s->vtd_pasid_as, + vtd_flush_pasid, &pc_info); +} + static bool vtd_process_pasid_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { + uint16_t domain_id; + uint32_t pasid; + VTDPASIDCacheInfo pc_info; + if ((inv_desc->val[0] & VTD_INV_DESC_PASIDC_RSVD_VAL0) || (inv_desc->val[1] & VTD_INV_DESC_PASIDC_RSVD_VAL1) || (inv_desc->val[2] & VTD_INV_DESC_PASIDC_RSVD_VAL2) || @@ -2433,14 +2881,26 @@ static bool vtd_process_pasid_desc(IntelIOMMUState *s, return false; } + domain_id = VTD_INV_DESC_PASIDC_DID(inv_desc->val[0]); + pasid = VTD_INV_DESC_PASIDC_PASID(inv_desc->val[0]); + switch (inv_desc->val[0] & VTD_INV_DESC_PASIDC_G) { case VTD_INV_DESC_PASIDC_DSI: + trace_vtd_pasid_cache_dsi(domain_id); + pc_info.type = VTD_PASID_CACHE_DOMSI; + pc_info.domain_id = domain_id; break; case VTD_INV_DESC_PASIDC_PASID_SI: + /* PASID selective implies a DID selective */ + pc_info.type = VTD_PASID_CACHE_PASIDSI; + pc_info.domain_id = domain_id; + pc_info.pasid = pasid; break; case VTD_INV_DESC_PASIDC_GLOBAL: + trace_vtd_pasid_cache_gsi(); + pc_info.type = VTD_PASID_CACHE_GLOBAL_INV; break; default: @@ -2449,6 +2909,7 @@ static bool vtd_process_pasid_desc(IntelIOMMUState *s, return false; } + vtd_pasid_cache_sync(s, &pc_info); return true; } @@ -3763,6 +4224,7 @@ static int vtd_dev_set_iommu_context(PCIBus *bus, void *opaque, vtd_dev_icx->devfn = (uint8_t)devfn; vtd_dev_icx->iommu_state = s; vtd_dev_icx->iommu_ctx = iommu_ctx; + QLIST_INSERT_HEAD(&s->vtd_dev_icx_list, vtd_dev_icx, next); vtd_iommu_unlock(s); @@ -3782,7 +4244,10 @@ static void vtd_dev_unset_iommu_context(PCIBus *bus, void *opaque, int devfn) vtd_iommu_lock(s); vtd_dev_icx = vtd_bus->dev_icx[devfn]; - g_free(vtd_dev_icx); + if (vtd_dev_icx) { + QLIST_REMOVE(vtd_dev_icx, next); + g_free(vtd_dev_icx); + } vtd_bus->dev_icx[devfn] = NULL; vtd_iommu_unlock(s); @@ -4203,6 +4668,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) } QLIST_INIT(&s->vtd_as_with_notifiers); + QLIST_INIT(&s->vtd_dev_icx_list); qemu_mutex_init(&s->iommu_lock); s->cap_finalized = false; memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); @@ -4229,6 +4695,9 @@ static void vtd_realize(DeviceState *dev, Error **errp) g_free, g_free); s->vtd_as_by_busptr = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal, g_free, g_free); + s->vtd_pasid_as = g_hash_table_new_full(vtd_pasid_as_key_hash, + vtd_pasid_as_key_equal, + g_free, g_free); vtd_init(s); sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, Q35_HOST_BRIDGE_IOMMU_ADDR); pci_setup_iommu(bus, &vtd_iommu_ops, dev); diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 3c8853ab88..a5d81e623b 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -326,6 +326,7 @@ typedef enum VTDFaultReason { VTD_FR_IR_SID_ERR = 0x26, /* Invalid Source-ID */ VTD_FR_PASID_TABLE_INV = 0x58, /*Invalid PASID table entry */ + VTD_FR_PASID_ENTRY_P = 0x59, /* The Present(P) field of pasidt-entry is 0 */ /* This is not a normal fault reason. We use this to indicate some faults * that are not referenced by the VT-d specification. @@ -530,10 +531,29 @@ typedef struct VTDRootEntry VTDRootEntry; #define VTD_CTX_ENTRY_LEGACY_SIZE 16 #define VTD_CTX_ENTRY_SCALABLE_SIZE 32 +#define VTD_SM_CONTEXT_ENTRY_PDTS(val) (((val) >> 9) & 0x3) #define VTD_SM_CONTEXT_ENTRY_RID2PASID_MASK 0xfffff #define VTD_SM_CONTEXT_ENTRY_RSVD_VAL0(aw) (0x1e0ULL | ~VTD_HAW_MASK(aw)) #define VTD_SM_CONTEXT_ENTRY_RSVD_VAL1 0xffffffffffe00000ULL +typedef enum VTDPCInvType { + /* force reset all */ + VTD_PASID_CACHE_FORCE_RESET = 0, + /* pasid cache invalidation rely on guest PASID entry */ + VTD_PASID_CACHE_GLOBAL_INV, + VTD_PASID_CACHE_DOMSI, + VTD_PASID_CACHE_PASIDSI, +} VTDPCInvType; + +struct VTDPASIDCacheInfo { + VTDPCInvType type; + uint16_t domain_id; + uint32_t pasid; + VTDBus *vtd_bus; + uint16_t devfn; +}; +typedef struct VTDPASIDCacheInfo VTDPASIDCacheInfo; + /* PASID Table Related Definitions */ #define VTD_PASID_DIR_BASE_ADDR_MASK (~0xfffULL) #define VTD_PASID_TABLE_BASE_ADDR_MASK (~0xfffULL) @@ -545,6 +565,7 @@ typedef struct VTDRootEntry VTDRootEntry; #define VTD_PASID_TABLE_BITS_MASK (0x3fULL) #define VTD_PASID_TABLE_INDEX(pasid) ((pasid) & VTD_PASID_TABLE_BITS_MASK) #define VTD_PASID_ENTRY_FPD (1ULL << 1) /* Fault Processing Disable */ +#define VTD_PASID_TBL_ENTRY_NUM (1ULL << 6) /* PASID Granular Translation Type Mask */ #define VTD_PASID_ENTRY_P 1ULL diff --git a/hw/i386/trace-events b/hw/i386/trace-events index f7cd4e5656..60d20c1335 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -23,6 +23,7 @@ vtd_inv_qi_tail(uint16_t head) "write tail %d" vtd_inv_qi_fetch(void) "" vtd_context_cache_reset(void) "" vtd_pasid_cache_gsi(void) "" +vtd_pasid_cache_reset(void) "" vtd_pasid_cache_dsi(uint16_t domain) "Domian slective PC invalidation domain 0x%"PRIx16 vtd_pasid_cache_psi(uint16_t domain, uint32_t pasid) "PASID slective PC invalidation domain 0x%"PRIx16" pasid 0x%"PRIx32 vtd_re_not_present(uint8_t bus) "Root entry bus %"PRIu8" not present" diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index cca9c821fe..10dabff6b5 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -64,6 +64,8 @@ typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress; typedef struct VTDPASIDDirEntry VTDPASIDDirEntry; typedef struct VTDPASIDEntry VTDPASIDEntry; typedef struct VTDHostIOMMUContext VTDHostIOMMUContext; +typedef struct VTDPASIDCacheEntry VTDPASIDCacheEntry; +typedef struct VTDPASIDAddressSpace VTDPASIDAddressSpace; /* Context-Entry */ struct VTDContextEntry { @@ -96,6 +98,26 @@ struct VTDPASIDEntry { uint64_t val[8]; }; +struct pasid_key { + uint32_t pasid; + uint16_t sid; +}; + +struct VTDPASIDCacheEntry { + struct VTDPASIDEntry pasid_entry; +}; + +struct VTDPASIDAddressSpace { + VTDBus *vtd_bus; + uint8_t devfn; + AddressSpace as; + uint32_t pasid; + IntelIOMMUState *iommu_state; + VTDContextCacheEntry context_cache_entry; + QLIST_ENTRY(VTDPASIDAddressSpace) next; + VTDPASIDCacheEntry pasid_cache_entry; +}; + struct VTDAddressSpace { PCIBus *bus; uint8_t devfn; @@ -117,6 +139,7 @@ struct VTDHostIOMMUContext { uint8_t devfn; HostIOMMUContext *iommu_ctx; IntelIOMMUState *iommu_state; + QLIST_ENTRY(VTDHostIOMMUContext) next; }; struct VTDBus { @@ -268,9 +291,13 @@ struct IntelIOMMUState { GHashTable *vtd_as_by_busptr; /* VTDBus objects indexed by PCIBus* reference */ VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */ + GHashTable *vtd_pasid_as; /* VTDPASIDAddressSpace instances */ /* list of registered notifiers */ QLIST_HEAD(, VTDAddressSpace) vtd_as_with_notifiers; + /* list of VTDHostIOMMUContexts */ + QLIST_HEAD(, VTDHostIOMMUContext) vtd_dev_icx_list; + /* interrupt remapping */ bool intr_enabled; /* Whether guest enabled IR */ dma_addr_t intr_root; /* Interrupt remapping table pointer */ @@ -295,6 +322,7 @@ struct IntelIOMMUState { * - per-IOMMU IOTLB caches * - context entry cache in VTDAddressSpace * - HostIOMMUContext pointer cached in vIOMMU + * - PASID cache in VTDPASIDAddressSpace */ QemuMutex iommu_lock; }; From patchwork Tue Mar 2 20:38:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446019 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcQH6yYLz9sS8 for ; Tue, 2 Mar 2021 23:49:11 +1100 (AEDT) Received: from localhost ([::1]:57166 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4Sb-0008IK-TS for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:49:09 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33218) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Kf-0008GC-Ct for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:57 -0500 Received: from mga12.intel.com ([192.55.52.136]:6965) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Kd-0002tl-1X for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:40:57 -0500 IronPort-SDR: NlgPbcbyopHmjl2UtO+0UKY+OQE+4YLeqExkKUQ5OVpIOP+Ih9afWsAC3Xif0Yte530IxcGf9U F05Rnd9/dsyA== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="166033900" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="166033900" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:53 -0800 IronPort-SDR: NOz9yPACrKdCsl/gGhPEL35jFAlBQ57KONWKubiEuZy3+F1AilLc0vxKxEiCBhCh7Z2sXDtK4t 7PIKDqBrH/jA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473057" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:49 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 18/25] intel_iommu: bind/unbind guest page table to host Date: Wed, 3 Mar 2021 04:38:20 +0800 Message-Id: <20210302203827.437645-19-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.136; envelope-from=yi.l.liu@intel.com; helo=mga12.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch captures the guest PASID table entry modifications and propagates the changes to host to setup dual stage DMA translation. The guest page table is configured as 1st level page table (GVA->GPA) whose translation result would further go through host VT-d 2nd level page table(GPA->HPA) under nested translation mode. This is the key part of vSVA support, and also a key to support IOVA over 1st- level page table for Intel VT-d in virtualization environment. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Signed-off-by: Liu Yi L --- rfcv10 -> rfcv11: *) Add @error_happened in struct VTDPASIDCacheInfo to track the bind/unbind failure, and return to guest. --- hw/i386/intel_iommu.c | 138 +++++++++++++++++++++++++++++---- hw/i386/intel_iommu_internal.h | 19 +++++ 2 files changed, 143 insertions(+), 14 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index a8f895807a..0fdc2c6e82 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -43,6 +43,7 @@ #include #include #include "qemu/jhash.h" +#include int ioasid_fd = -1; uint32_t ioasid_bits; @@ -705,6 +706,24 @@ static inline uint32_t vtd_sm_ce_get_pdt_entry_num(VTDContextEntry *ce) return 1U << (VTD_SM_CONTEXT_ENTRY_PDTS(ce->val[0]) + 7); } +static inline uint32_t vtd_pe_get_fl_aw(VTDPASIDEntry *pe) +{ + return 48 + ((pe->val[2] >> 2) & VTD_SM_PASID_ENTRY_FLPM) * 9; +} + +static inline dma_addr_t vtd_pe_get_flpt_base(VTDPASIDEntry *pe) +{ + return pe->val[2] & VTD_SM_PASID_ENTRY_FLPTPTR; +} + +static inline void pasid_cache_info_set_error(VTDPASIDCacheInfo *pc_info) +{ + if (pc_info->error_happened) { + return; + } + pc_info->error_happened = true; +} + static inline bool vtd_pdire_present(VTDPASIDDirEntry *pdire) { return pdire->val & 1; @@ -1875,6 +1894,85 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s) vtd_iommu_replay_all(s); } +/** + * Caller should hold iommu_lock. + */ +static int vtd_bind_guest_pasid(IntelIOMMUState *s, VTDBus *vtd_bus, + int devfn, int pasid, VTDPASIDEntry *pe, + VTDPASIDOp op) +{ + VTDHostIOMMUContext *vtd_dev_icx; + HostIOMMUContext *iommu_ctx; + int ret = -1; + + vtd_dev_icx = vtd_bus->dev_icx[devfn]; + if (!vtd_dev_icx) { + /* means no need to go further, e.g. for emulated devices */ + return 0; + } + + iommu_ctx = vtd_dev_icx->iommu_ctx; + if (!iommu_ctx) { + return -EINVAL; + } + + switch (op) { + case VTD_PASID_BIND: + { + struct iommu_gpasid_bind_data *g_bind_data; + + g_bind_data = g_malloc0(sizeof(*g_bind_data)); + + g_bind_data->argsz = sizeof(*g_bind_data); + g_bind_data->version = IOMMU_GPASID_BIND_VERSION_1; + g_bind_data->format = IOMMU_PASID_FORMAT_INTEL_VTD; + g_bind_data->gpgd = vtd_pe_get_flpt_base(pe); + g_bind_data->addr_width = vtd_pe_get_fl_aw(pe); + g_bind_data->hpasid = pasid; + g_bind_data->gpasid = pasid; + g_bind_data->flags |= IOMMU_SVA_GPASID_VAL; + g_bind_data->vendor.vtd.flags = + (VTD_SM_PASID_ENTRY_SRE_BIT(pe->val[2]) ? + IOMMU_SVA_VTD_GPASID_SRE : 0) + | (VTD_SM_PASID_ENTRY_EAFE_BIT(pe->val[2]) ? + IOMMU_SVA_VTD_GPASID_EAFE : 0) + | (VTD_SM_PASID_ENTRY_PCD_BIT(pe->val[1]) ? + IOMMU_SVA_VTD_GPASID_PCD : 0) + | (VTD_SM_PASID_ENTRY_PWT_BIT(pe->val[1]) ? + IOMMU_SVA_VTD_GPASID_PWT : 0) + | (VTD_SM_PASID_ENTRY_EMTE_BIT(pe->val[1]) ? + IOMMU_SVA_VTD_GPASID_EMTE : 0) + | (VTD_SM_PASID_ENTRY_CD_BIT(pe->val[1]) ? + IOMMU_SVA_VTD_GPASID_CD : 0); + g_bind_data->vendor.vtd.pat = VTD_SM_PASID_ENTRY_PAT(pe->val[1]); + g_bind_data->vendor.vtd.emt = VTD_SM_PASID_ENTRY_EMT(pe->val[1]); + ret = host_iommu_ctx_bind_stage1_pgtbl(iommu_ctx, g_bind_data); + g_free(g_bind_data); + break; + } + case VTD_PASID_UNBIND: + { + struct iommu_gpasid_bind_data *g_unbind_data; + + g_unbind_data = g_malloc0(sizeof(*g_unbind_data)); + + g_unbind_data->argsz = sizeof(*g_unbind_data); + g_unbind_data->version = IOMMU_GPASID_BIND_VERSION_1; + g_unbind_data->format = IOMMU_PASID_FORMAT_INTEL_VTD; + g_unbind_data->hpasid = pasid; + ret = host_iommu_ctx_unbind_stage1_pgtbl(iommu_ctx, g_unbind_data); + g_free(g_unbind_data); + break; + } + default: + error_report_once("Unknown VTDPASIDOp!!!\n"); + break; + } + + + return ret; +} + /* Do a context-cache device-selective invalidation. * @func_mask: FM field after shifting */ @@ -2503,22 +2601,22 @@ static bool vtd_pasid_entry_compare(VTDPASIDEntry *p1, VTDPASIDEntry *p2) * This function fills in the pasid entry in &vtd_pasid_as. Caller * of this function should hold iommu_lock. */ -static void vtd_fill_pe_in_cache(IntelIOMMUState *s, - VTDPASIDAddressSpace *vtd_pasid_as, - VTDPASIDEntry *pe) +static int vtd_fill_pe_in_cache(IntelIOMMUState *s, + VTDPASIDAddressSpace *vtd_pasid_as, + VTDPASIDEntry *pe) { VTDPASIDCacheEntry *pc_entry = &vtd_pasid_as->pasid_cache_entry; if (vtd_pasid_entry_compare(pe, &pc_entry->pasid_entry)) { /* No need to go further as cached pasid entry is latest */ - return; + return 0; } pc_entry->pasid_entry = *pe; - /* - * TODO: - * - send pasid bind to host for passthru devices - */ + return vtd_bind_guest_pasid(s, vtd_pasid_as->vtd_bus, + vtd_pasid_as->devfn, + vtd_pasid_as->pasid, + pe, VTD_PASID_BIND); } /** @@ -2581,7 +2679,10 @@ static gboolean vtd_flush_pasid(gpointer key, gpointer value, goto remove; } - vtd_fill_pe_in_cache(s, vtd_pasid_as, &pe); + if (vtd_fill_pe_in_cache(s, vtd_pasid_as, &pe)) { + pasid_cache_info_set_error(pc_info); + } + /* * TODO: * - when pasid-base-iotlb(piotlb) infrastructure is ready, @@ -2591,10 +2692,14 @@ static gboolean vtd_flush_pasid(gpointer key, gpointer value, remove: /* * TODO: - * - send pasid bind to host for passthru devices * - when pasid-base-iotlb(piotlb) infrastructure is ready, * should invalidate QEMU piotlb togehter with this change. */ + if (vtd_bind_guest_pasid(s, vtd_bus, devfn, + pasid, NULL, VTD_PASID_UNBIND)) { + pasid_cache_info_set_error(pc_info); + } + return true; } @@ -2672,7 +2777,9 @@ static void vtd_sm_pasid_table_walk_one(IntelIOMMUState *s, pasid = pasid_next; continue; } - vtd_fill_pe_in_cache(s, vtd_pasid_as, &pe); + if (vtd_fill_pe_in_cache(s, vtd_pasid_as, &pe)) { + pasid_cache_info_set_error(info); + } } pasid = pasid_next; } @@ -2779,6 +2886,9 @@ static void vtd_replay_guest_pasid_bindings(IntelIOMMUState *s, walk_info.devfn = vtd_dev_icx->devfn; vtd_replay_pasid_bind_for_dev(s, start, end, &walk_info); } + if (walk_info.error_happened) { + pasid_cache_info_set_error(pc_info); + } } /** @@ -2846,7 +2956,7 @@ static void vtd_pasid_cache_sync(IntelIOMMUState *s, */ static void vtd_pasid_cache_reset(IntelIOMMUState *s) { - VTDPASIDCacheInfo pc_info; + VTDPASIDCacheInfo pc_info = { .error_happened = false, }; trace_vtd_pasid_cache_reset(); @@ -2868,9 +2978,9 @@ static void vtd_pasid_cache_reset(IntelIOMMUState *s) static bool vtd_process_pasid_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { + VTDPASIDCacheInfo pc_info = { .error_happened = false, }; uint16_t domain_id; uint32_t pasid; - VTDPASIDCacheInfo pc_info; if ((inv_desc->val[0] & VTD_INV_DESC_PASIDC_RSVD_VAL0) || (inv_desc->val[1] & VTD_INV_DESC_PASIDC_RSVD_VAL1) || @@ -2910,7 +3020,7 @@ static bool vtd_process_pasid_desc(IntelIOMMUState *s, } vtd_pasid_cache_sync(s, &pc_info); - return true; + return !pc_info.error_happened ? true : false; } static bool vtd_process_inv_iec_desc(IntelIOMMUState *s, diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index a5d81e623b..e4c7b23455 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -536,6 +536,13 @@ typedef struct VTDRootEntry VTDRootEntry; #define VTD_SM_CONTEXT_ENTRY_RSVD_VAL0(aw) (0x1e0ULL | ~VTD_HAW_MASK(aw)) #define VTD_SM_CONTEXT_ENTRY_RSVD_VAL1 0xffffffffffe00000ULL +enum VTDPASIDOp { + VTD_PASID_BIND, + VTD_PASID_UNBIND, + VTD_OP_NUM +}; +typedef enum VTDPASIDOp VTDPASIDOp; + typedef enum VTDPCInvType { /* force reset all */ VTD_PASID_CACHE_FORCE_RESET = 0, @@ -551,6 +558,7 @@ struct VTDPASIDCacheInfo { uint32_t pasid; VTDBus *vtd_bus; uint16_t devfn; + bool error_happened; }; typedef struct VTDPASIDCacheInfo VTDPASIDCacheInfo; @@ -578,6 +586,17 @@ typedef struct VTDPASIDCacheInfo VTDPASIDCacheInfo; #define VTD_SM_PASID_ENTRY_AW 7ULL /* Adjusted guest-address-width */ #define VTD_SM_PASID_ENTRY_DID(val) ((val) & VTD_DOMAIN_ID_MASK) +#define VTD_SM_PASID_ENTRY_FLPM 3ULL +#define VTD_SM_PASID_ENTRY_FLPTPTR (~0xfffULL) +#define VTD_SM_PASID_ENTRY_SRE_BIT(val) (!!((val) & 1ULL)) +#define VTD_SM_PASID_ENTRY_EAFE_BIT(val) (!!(((val) >> 7) & 1ULL)) +#define VTD_SM_PASID_ENTRY_PCD_BIT(val) (!!(((val) >> 31) & 1ULL)) +#define VTD_SM_PASID_ENTRY_PWT_BIT(val) (!!(((val) >> 30) & 1ULL)) +#define VTD_SM_PASID_ENTRY_EMTE_BIT(val) (!!(((val) >> 26) & 1ULL)) +#define VTD_SM_PASID_ENTRY_CD_BIT(val) (!!(((val) >> 25) & 1ULL)) +#define VTD_SM_PASID_ENTRY_PAT(val) (((val) >> 32) & 0xFFFFFFFFULL) +#define VTD_SM_PASID_ENTRY_EMT(val) (((val) >> 27) & 0x7ULL) + /* Second Level Page Translation Pointer*/ #define VTD_SM_PASID_ENTRY_SLPTPTR (~0xfffULL) From patchwork Tue Mar 2 20:38:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446022 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcSY2n5Dz9sS8 for ; Tue, 2 Mar 2021 23:51:09 +1100 (AEDT) Received: from localhost ([::1]:34144 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4UV-00024J-44 for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:51:07 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33286) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Ko-0008Lf-4E for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:06 -0500 Received: from mga12.intel.com ([192.55.52.136]:6968) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Kh-0002u4-PR for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:04 -0500 IronPort-SDR: WcFUT+N2M+jpjPJupNlHaJgMx0w7wyzqT5IfkVZq5fNNVeipsOFmrWXBX2eGAL1YN87bAlSCPK 7ELz7BJvving== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="166033905" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="166033905" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:40:58 -0800 IronPort-SDR: mXRHSMgcZqB95hQHzTQpF0gcZqG+Vb6BNYkEfLN4uGDbq6V2qsH1kQvRj/rEt/lKDFsn6SHiEn AHQfltvlHQ0Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473080" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:53 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 19/25] intel_iommu: replay pasid binds after context cache invalidation Date: Wed, 3 Mar 2021 04:38:21 +0800 Message-Id: <20210302203827.437645-20-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.136; envelope-from=yi.l.liu@intel.com; helo=mga12.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch replays guest pasid bindings after context cache invalidation. This is a behavior to ensure safety. Actually, programmer should issue pasid cache invalidation with proper granularity after issuing a context cache invalidation. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Liu Yi L --- hw/i386/intel_iommu.c | 50 ++++++++++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 1 + hw/i386/trace-events | 1 + 3 files changed, 52 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 0fdc2c6e82..c99fd3b167 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -73,6 +73,10 @@ static void vtd_address_space_refresh_all(IntelIOMMUState *s); static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n); static void vtd_pasid_cache_reset(IntelIOMMUState *s); +static void vtd_pasid_cache_sync(IntelIOMMUState *s, + VTDPASIDCacheInfo *pc_info); +static void vtd_pasid_cache_devsi(IntelIOMMUState *s, + VTDBus *vtd_bus, uint16_t devfn); static void vtd_panic_require_caching_mode(void) { @@ -1875,7 +1879,10 @@ static void vtd_iommu_replay_all(IntelIOMMUState *s) static void vtd_context_global_invalidate(IntelIOMMUState *s) { + VTDPASIDCacheInfo pc_info = { .error_happened = false, }; + trace_vtd_inv_desc_cc_global(); + /* Protects context cache */ vtd_iommu_lock(s); s->context_cache_gen++; @@ -1892,6 +1899,9 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s) * VT-d emulation codes. */ vtd_iommu_replay_all(s); + + pc_info.type = VTD_PASID_CACHE_GLOBAL_INV; + vtd_pasid_cache_sync(s, &pc_info); } /** @@ -2030,6 +2040,21 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s, * happened. */ vtd_sync_shadow_page_table(vtd_as); + /* + * Per spec, context flush should also followed with PASID + * cache and iotlb flush. Regards to a device selective + * context cache invalidation: + * if (emaulted_device) + * invalidate pasid cahce and pasid-based iotlb + * else if (assigned_device) + * check if the device has been bound to any pasid + * invoke pasid_unbind regards to each bound pasid + * Here, we have vtd_pasid_cache_devsi() to invalidate pasid + * caches, while for piotlb in QEMU, we don't have it yet, so + * no handling. For assigned device, host iommu driver would + * flush piotlb when a pasid unbind is pass down to it. + */ + vtd_pasid_cache_devsi(s, vtd_bus, devfn_it); } } } @@ -2656,6 +2681,12 @@ static gboolean vtd_flush_pasid(gpointer key, gpointer value, /* Fall through */ case VTD_PASID_CACHE_GLOBAL_INV: break; + case VTD_PASID_CACHE_DEVSI: + if (pc_info->vtd_bus != vtd_bus || + pc_info->devfn != devfn) { + return false; + } + break; default: error_report("invalid pc_info->type"); abort(); @@ -2863,6 +2894,11 @@ static void vtd_replay_guest_pasid_bindings(IntelIOMMUState *s, case VTD_PASID_CACHE_GLOBAL_INV: /* loop all assigned devices */ break; + case VTD_PASID_CACHE_DEVSI: + walk_info.vtd_bus = pc_info->vtd_bus; + walk_info.devfn = pc_info->devfn; + vtd_replay_pasid_bind_for_dev(s, start, end, &walk_info); + return; case VTD_PASID_CACHE_FORCE_RESET: /* For force reset, no need to go further replay */ return; @@ -2951,6 +2987,20 @@ static void vtd_pasid_cache_sync(IntelIOMMUState *s, vtd_iommu_unlock(s); } +static void vtd_pasid_cache_devsi(IntelIOMMUState *s, + VTDBus *vtd_bus, uint16_t devfn) +{ + VTDPASIDCacheInfo pc_info = { .error_happened = false, }; + + trace_vtd_pasid_cache_devsi(devfn); + + pc_info.type = VTD_PASID_CACHE_DEVSI; + pc_info.vtd_bus = vtd_bus; + pc_info.devfn = devfn; + + vtd_pasid_cache_sync(s, &pc_info); +} + /** * Caller of this function should hold iommu_lock */ diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index e4c7b23455..eae57f457c 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -548,6 +548,7 @@ typedef enum VTDPCInvType { VTD_PASID_CACHE_FORCE_RESET = 0, /* pasid cache invalidation rely on guest PASID entry */ VTD_PASID_CACHE_GLOBAL_INV, + VTD_PASID_CACHE_DEVSI, VTD_PASID_CACHE_DOMSI, VTD_PASID_CACHE_PASIDSI, } VTDPCInvType; diff --git a/hw/i386/trace-events b/hw/i386/trace-events index 60d20c1335..3853fa8e5a 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -26,6 +26,7 @@ vtd_pasid_cache_gsi(void) "" vtd_pasid_cache_reset(void) "" vtd_pasid_cache_dsi(uint16_t domain) "Domian slective PC invalidation domain 0x%"PRIx16 vtd_pasid_cache_psi(uint16_t domain, uint32_t pasid) "PASID slective PC invalidation domain 0x%"PRIx16" pasid 0x%"PRIx32 +vtd_pasid_cache_devsi(uint16_t devfn) "Dev selective PC invalidation dev: 0x%"PRIx16 vtd_re_not_present(uint8_t bus) "Root entry bus %"PRIu8" not present" vtd_ce_not_present(uint8_t bus, uint8_t devfn) "Context entry bus %"PRIu8" devfn %"PRIu8" not present" vtd_iotlb_page_hit(uint16_t sid, uint64_t addr, uint64_t slpte, uint16_t domain) "IOTLB page hit sid 0x%"PRIx16" iova 0x%"PRIx64" slpte 0x%"PRIx64" domain 0x%"PRIx16 From patchwork Tue Mar 2 20:38:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446023 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcTb1pP0z9sS8 for ; Tue, 2 Mar 2021 23:52:02 +1100 (AEDT) Received: from localhost ([::1]:37226 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4VM-0003YS-I8 for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:52:00 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33314) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Ks-0008Mr-59 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:12 -0500 Received: from mga12.intel.com ([192.55.52.136]:6975) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Kn-0002uc-U3 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:08 -0500 IronPort-SDR: ZNPTadc3s26+8QfKjfaLXFFvAt1sW06thD+O7SWSMcP27Qzo+qeA8DjOfum1iGxh4FOWzux8hY l1oElDu4/+VQ== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="166033920" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="166033920" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:41:03 -0800 IronPort-SDR: Zu6Im+dAAj85rFucgp/CyKLe4X1ICYrGII5WTFMw4LhqjBBGPZPJZ4NNsZu2vltSh1NTRU5aC+ nhJi+Y3e1UbA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473099" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:40:58 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 20/25] intel_iommu: do not pass down pasid bind for PASID #0 Date: Wed, 3 Mar 2021 04:38:22 +0800 Message-Id: <20210302203827.437645-21-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.136; envelope-from=yi.l.liu@intel.com; helo=mga12.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" RID_PASID field was introduced in VT-d 3.0 spec, it is used for DMA requests w/o PASID in scalable mode VT-d. It is also known as IOVA. And in VT-d 3.1 spec, there is definition on it: "Implementations not supporting RID_PASID capability (ECAP_REG.RPS is 0b), use a PASID value of 0 to perform address translation for requests without PASID." This patch adds a check against the PASIDs which are going to be bound to device. For PASID #0, it is not necessary to pass down pasid bind request for it since PASID #0 is used as RID_PASID for DMA requests without pasid. Further reason is current Intel vIOMMU supports gIOVA by shadowing guest 2nd level page table. However, in future, if guest IOMMU driver uses 1st level page table to store IOVA mappings, then guest IOVA support will also be done via nested translation. When gIOVA is over FLPT, then vIOMMU should pass down the pasid bind request for PASID #0 to host, host needs to bind the guest IOVA page table to a proper PASID. e.g. PASID value in RID_PASID field for PF/VF if ECAP_REG.RPS is clear or default PASID for ADI (Assignable Device Interface in Scalable IOV solution). IOVA over FLPT support on Intel VT-d: https://lore.kernel.org/linux-iommu/20191219031634.15168-1-baolu.lu@linux.intel.com/ Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Reviewed-by: Peter Xu Signed-off-by: Liu Yi L --- hw/i386/intel_iommu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index c99fd3b167..740dc63090 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1915,6 +1915,16 @@ static int vtd_bind_guest_pasid(IntelIOMMUState *s, VTDBus *vtd_bus, HostIOMMUContext *iommu_ctx; int ret = -1; + if (pasid < VTD_HPASID_MIN) { + /* + * If pasid < VTD_HPASID_MIN, this pasid is not allocated + * from host. No need to pass down the changes on it to host. + * TODO: when IOVA over FLPT is ready, this switch should be + * refined. + */ + return 0; + } + vtd_dev_icx = vtd_bus->dev_icx[devfn]; if (!vtd_dev_icx) { /* means no need to go further, e.g. for emulated devices */ From patchwork Tue Mar 2 20:38:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446034 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Dqclm4dw4z9sS8 for ; Wed, 3 Mar 2021 00:04:20 +1100 (AEDT) Received: from localhost ([::1]:35254 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4hG-0006p7-8X for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 08:04:18 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33382) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Kz-0008P8-8q for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:17 -0500 Received: from mga12.intel.com ([192.55.52.136]:6968) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Ks-0002u4-0n for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:16 -0500 IronPort-SDR: wd+F9bJB52+61YQ0vZZfa2XGf7DEmOrSkC5wa9g7NT4TDkjzVmWMm+Z9njf/0WGoZAGWXJwWeC 1W16AZ9grx5Q== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="166033931" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="166033931" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:41:07 -0800 IronPort-SDR: qOIBtZvRmYH+IFP8TK8bvwTTGzo3zNwuB0JhTN14LwMPZWdSEAGveWZDRgVaDLLUukKgPKmjpo ptxS847I/gNA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473129" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:41:03 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 21/25] vfio: add support for flush iommu stage-1 cache Date: Wed, 3 Mar 2021 04:38:23 +0800 Message-Id: <20210302203827.437645-22-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.136; envelope-from=yi.l.liu@intel.com; helo=mga12.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds flush_stage1_cache() definition in HostIOMUContextClass. And adds corresponding implementation in VFIO. This is to expose a way for vIOMMU to flush stage-1 cache in host side since guest owns stage-1 translation structures in dual stage DMA translation configuration. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Alex Williamson Acked-by: Peter Xu Signed-off-by: Liu Yi L --- hw/iommu/host_iommu_context.c | 19 +++++++++++++++++++ hw/vfio/common.c | 24 ++++++++++++++++++++++++ include/hw/iommu/host_iommu_context.h | 8 ++++++++ 3 files changed, 51 insertions(+) diff --git a/hw/iommu/host_iommu_context.c b/hw/iommu/host_iommu_context.c index d7139bcb86..59f5e7af9e 100644 --- a/hw/iommu/host_iommu_context.c +++ b/hw/iommu/host_iommu_context.c @@ -69,6 +69,25 @@ int host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, return hicxc->unbind_stage1_pgtbl(iommu_ctx, unbind); } +int host_iommu_ctx_flush_stage1_cache(HostIOMMUContext *iommu_ctx, + struct iommu_cache_invalidate_info *cache) +{ + HostIOMMUContextClass *hicxc; + + hicxc = HOST_IOMMU_CONTEXT_GET_CLASS(iommu_ctx); + + if (!hicxc) { + return -EINVAL; + } + + if (!(iommu_ctx->info->features & IOMMU_NESTING_FEAT_CACHE_INVLD) || + !hicxc->flush_stage1_cache) { + return -EINVAL; + } + + return hicxc->flush_stage1_cache(iommu_ctx, cache); +} + void host_iommu_ctx_init(void *_iommu_ctx, size_t instance_size, const char *mrtypename, struct iommu_nesting_info *info) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index a12708bcb7..122866fa85 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1623,6 +1623,29 @@ static int vfio_host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, return ret; } +static int vfio_host_iommu_ctx_flush_stage1_cache(HostIOMMUContext *iommu_ctx, + struct iommu_cache_invalidate_info *cache) +{ + VFIOContainer *container = container_of(iommu_ctx, + VFIOContainer, iommu_ctx); + struct vfio_iommu_type1_nesting_op *op; + unsigned long argsz; + int ret = 0; + + argsz = sizeof(*op) + sizeof(*cache); + op = g_malloc0(argsz); + op->argsz = argsz; + op->flags = VFIO_IOMMU_NESTING_OP_CACHE_INVLD; + memcpy(&op->data, cache, sizeof(*cache)); + + if (ioctl(container->fd, VFIO_IOMMU_NESTING_OP, op)) { + ret = -errno; + error_report("%s: iommu cache flush failed: %m", __func__); + } + g_free(op); + return ret; +} + /** * Get iommu info from host. Caller of this funcion should free * the memory pointed by the returned pointer stored in @info @@ -2389,6 +2412,7 @@ static void vfio_host_iommu_context_class_init(ObjectClass *klass, hicxc->bind_stage1_pgtbl = vfio_host_iommu_ctx_bind_stage1_pgtbl; hicxc->unbind_stage1_pgtbl = vfio_host_iommu_ctx_unbind_stage1_pgtbl; + hicxc->flush_stage1_cache = vfio_host_iommu_ctx_flush_stage1_cache; } static const TypeInfo vfio_host_iommu_context_info = { diff --git a/include/hw/iommu/host_iommu_context.h b/include/hw/iommu/host_iommu_context.h index 3498a3e25d..8b1171fbf9 100644 --- a/include/hw/iommu/host_iommu_context.h +++ b/include/hw/iommu/host_iommu_context.h @@ -55,6 +55,12 @@ typedef struct HostIOMMUContextClass { /* Undo a previous bind. @unbind specifies the unbind info. */ int (*unbind_stage1_pgtbl)(HostIOMMUContext *iommu_ctx, struct iommu_gpasid_bind_data *unbind); + /* + * Propagate stage-1 cache flush to host IOMMU, cache + * info specifid in @cache + */ + int (*flush_stage1_cache)(HostIOMMUContext *iommu_ctx, + struct iommu_cache_invalidate_info *cache); } HostIOMMUContextClass; /* @@ -70,6 +76,8 @@ int host_iommu_ctx_bind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, struct iommu_gpasid_bind_data *bind); int host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *iommu_ctx, struct iommu_gpasid_bind_data *unbind); +int host_iommu_ctx_flush_stage1_cache(HostIOMMUContext *iommu_ctx, + struct iommu_cache_invalidate_info *cache); void host_iommu_ctx_init(void *_iommu_ctx, size_t instance_size, const char *mrtypename, struct iommu_nesting_info *info); From patchwork Tue Mar 2 20:38:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446028 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcWp6Qb6z9sS8 for ; Tue, 2 Mar 2021 23:53:58 +1100 (AEDT) Received: from localhost ([::1]:45606 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4XE-00074y-Qz for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:53:56 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33426) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4L1-0008Rt-9A for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:19 -0500 Received: from mga12.intel.com ([192.55.52.136]:6975) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Kv-0002uc-0u for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:19 -0500 IronPort-SDR: JzqPmmqN92CcIwDR1u3gfTo+QOjeQxKE6ZxJ+d0S8lCxWov7WRYzykukF8DF9BtOl52uAs0URz 6EHgsrWCbGcg== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="166033945" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="166033945" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:41:12 -0800 IronPort-SDR: mrfL1o7bgIg81x7iND/b/W5NLqXKxtQYDhF8QG+9sUwhr96Sq9kYXVniPkDUzQApM3U2mFI+cX StwnrH+aJFEw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473147" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:41:07 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 22/25] intel_iommu: process PASID-based iotlb invalidation Date: Wed, 3 Mar 2021 04:38:24 +0800 Message-Id: <20210302203827.437645-23-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.136; envelope-from=yi.l.liu@intel.com; helo=mga12.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds the basic PASID-based iotlb (piotlb) invalidation support. piotlb is used during walking Intel VT-d 1st level page table. This patch only adds the basic processing. Detailed handling will be added in next patch. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Reviewed-by: Peter Xu Signed-off-by: Liu Yi L --- hw/i386/intel_iommu.c | 53 ++++++++++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 13 +++++++++ 2 files changed, 66 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 740dc63090..b709440b15 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3083,6 +3083,55 @@ static bool vtd_process_pasid_desc(IntelIOMMUState *s, return !pc_info.error_happened ? true : false; } +static void vtd_piotlb_pasid_invalidate(IntelIOMMUState *s, + uint16_t domain_id, + uint32_t pasid) +{ +} + +static void vtd_piotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id, + uint32_t pasid, hwaddr addr, uint8_t am, + bool ih) +{ +} + +static bool vtd_process_piotlb_desc(IntelIOMMUState *s, + VTDInvDesc *inv_desc) +{ + uint16_t domain_id; + uint32_t pasid; + uint8_t am; + hwaddr addr; + + if ((inv_desc->val[0] & VTD_INV_DESC_PIOTLB_RSVD_VAL0) || + (inv_desc->val[1] & VTD_INV_DESC_PIOTLB_RSVD_VAL1)) { + error_report_once("non-zero-field-in-piotlb_inv_desc hi: 0x%" PRIx64 + " lo: 0x%" PRIx64, inv_desc->val[1], inv_desc->val[0]); + return false; + } + + domain_id = VTD_INV_DESC_PIOTLB_DID(inv_desc->val[0]); + pasid = VTD_INV_DESC_PIOTLB_PASID(inv_desc->val[0]); + switch (inv_desc->val[0] & VTD_INV_DESC_IOTLB_G) { + case VTD_INV_DESC_PIOTLB_ALL_IN_PASID: + vtd_piotlb_pasid_invalidate(s, domain_id, pasid); + break; + + case VTD_INV_DESC_PIOTLB_PSI_IN_PASID: + am = VTD_INV_DESC_PIOTLB_AM(inv_desc->val[1]); + addr = (hwaddr) VTD_INV_DESC_PIOTLB_ADDR(inv_desc->val[1]); + vtd_piotlb_page_invalidate(s, domain_id, pasid, addr, am, + VTD_INV_DESC_PIOTLB_IH(inv_desc->val[1])); + break; + + default: + error_report_once("Invalid granularity in P-IOTLB desc hi: 0x%" PRIx64 + " lo: 0x%" PRIx64, inv_desc->val[1], inv_desc->val[0]); + return false; + } + return true; +} + static bool vtd_process_inv_iec_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { @@ -3198,6 +3247,10 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) break; case VTD_INV_DESC_PIOTLB: + trace_vtd_inv_desc("p-iotlb", inv_desc.val[1], inv_desc.val[0]); + if (!vtd_process_piotlb_desc(s, &inv_desc)) { + return false; + } break; case VTD_INV_DESC_WAIT: diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index eae57f457c..24b5f934c3 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -476,6 +476,19 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_PASIDC_PASID_SI (1ULL << 4) #define VTD_INV_DESC_PASIDC_GLOBAL (3ULL << 4) +#define VTD_INV_DESC_PIOTLB_ALL_IN_PASID (2ULL << 4) +#define VTD_INV_DESC_PIOTLB_PSI_IN_PASID (3ULL << 4) + +#define VTD_INV_DESC_PIOTLB_RSVD_VAL0 0xfff000000000ffc0ULL +#define VTD_INV_DESC_PIOTLB_RSVD_VAL1 0xf80ULL + +#define VTD_INV_DESC_PIOTLB_PASID(val) (((val) >> 32) & 0xfffffULL) +#define VTD_INV_DESC_PIOTLB_DID(val) (((val) >> 16) & \ + VTD_DOMAIN_ID_MASK) +#define VTD_INV_DESC_PIOTLB_ADDR(val) ((val) & ~0xfffULL) +#define VTD_INV_DESC_PIOTLB_AM(val) ((val) & 0x3fULL) +#define VTD_INV_DESC_PIOTLB_IH(val) (((val) >> 6) & 0x1) + /* Information about page-selective IOTLB invalidate */ struct VTDIOTLBPageInvInfo { uint16_t domain_id; From patchwork Tue Mar 2 20:38:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446035 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Dqcq74ccXz9sS8 for ; Wed, 3 Mar 2021 00:07:15 +1100 (AEDT) Received: from localhost ([::1]:38806 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4k5-0000Ef-Dt for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 08:07:13 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33470) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4L2-0008WJ-VY for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:20 -0500 Received: from mga12.intel.com ([192.55.52.136]:6968) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4Kz-0002u4-T3 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:20 -0500 IronPort-SDR: c3qM5reThQOYHtp5U3iwhYw4PvKwSBdTHb2KgZ/y/foSPuhkEip0nluUuV6VqW/MGl+9FEelhc wu/PEraRAQHA== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="166033966" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="166033966" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:41:17 -0800 IronPort-SDR: ry6vW2O0Hnmty08Um75OoKIWLQePwpN4U1pQ/eFxpwBAX0KEq9FuaIvLtBcgriSsSlt34nTA5q 2NtzGJnzGFCA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473171" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:41:12 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 23/25] intel_iommu: propagate PASID-based iotlb invalidation to host Date: Wed, 3 Mar 2021 04:38:25 +0800 Message-Id: <20210302203827.437645-24-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.136; envelope-from=yi.l.liu@intel.com; helo=mga12.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch propagates PASID-based iotlb invalidation to host. Intel VT-d 3.0 supports nested translation in PASID granular. Guest SVA support could be implemented by configuring nested translation on specific PASID. This is also known as dual stage DMA translation. Under such configuration, guest owns the GVA->GPA translation which is configured as first level page table in host side for a specific pasid, and host owns GPA->HPA translation. As guest owns first level translation table, piotlb invalidation should be propagated to host since host IOMMU will cache first level page table related mappings during DMA address translation. This patch traps the guest PASID-based iotlb flush and propagate it to host. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Liu Yi L --- rfcv4 (v1) -> rfcv5 (v2): *) removed the valid check to vtd_pasid_as instance as rfcv5 ensures all vtd_pasid_as instances in hash table should be valid. --- hw/i386/intel_iommu.c | 113 +++++++++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 7 ++ 2 files changed, 120 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index b709440b15..915db7ad1f 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3083,16 +3083,129 @@ static bool vtd_process_pasid_desc(IntelIOMMUState *s, return !pc_info.error_happened ? true : false; } +/** + * Caller of this function should hold iommu_lock. + */ +static void vtd_invalidate_piotlb(IntelIOMMUState *s, + VTDBus *vtd_bus, + int devfn, + struct iommu_cache_invalidate_info *cache) +{ + VTDHostIOMMUContext *vtd_dev_icx; + HostIOMMUContext *iommu_ctx; + + vtd_dev_icx = vtd_bus->dev_icx[devfn]; + if (!vtd_dev_icx) { + goto out; + } + iommu_ctx = vtd_dev_icx->iommu_ctx; + if (!iommu_ctx) { + goto out; + } + if (host_iommu_ctx_flush_stage1_cache(iommu_ctx, cache)) { + error_report("Cache flush failed"); + } +out: + return; +} + +/** + * This function is a loop function for the s->vtd_pasid_as + * list with VTDPIOTLBInvInfo as execution filter. It propagates + * the piotlb invalidation to host. Caller of this function + * should hold iommu_lock. + */ +static void vtd_flush_pasid_iotlb(gpointer key, gpointer value, + gpointer user_data) +{ + VTDPIOTLBInvInfo *piotlb_info = user_data; + VTDPASIDAddressSpace *vtd_pasid_as = value; + VTDPASIDCacheEntry *pc_entry = &vtd_pasid_as->pasid_cache_entry; + uint16_t did; + + did = vtd_pe_get_domain_id(&pc_entry->pasid_entry); + + if ((piotlb_info->domain_id == did) && + (piotlb_info->pasid == vtd_pasid_as->pasid)) { + vtd_invalidate_piotlb(vtd_pasid_as->iommu_state, + vtd_pasid_as->vtd_bus, + vtd_pasid_as->devfn, + piotlb_info->cache_info); + } + + /* + * TODO: needs to add QEMU piotlb flush when QEMU piotlb + * infrastructure is ready. For now, it is enough for passthru + * devices. + */ +} + static void vtd_piotlb_pasid_invalidate(IntelIOMMUState *s, uint16_t domain_id, uint32_t pasid) { + VTDPIOTLBInvInfo piotlb_info; + struct iommu_cache_invalidate_info *cache_info; + + cache_info = g_malloc0(sizeof(*cache_info)); + + cache_info->argsz = sizeof(*cache_info); + cache_info->version = IOMMU_CACHE_INVALIDATE_INFO_VERSION_1; + cache_info->cache = IOMMU_CACHE_INV_TYPE_IOTLB; + cache_info->granularity = IOMMU_INV_GRANU_PASID; + cache_info->granu.pasid_info.pasid = pasid; + cache_info->granu.pasid_info.flags = IOMMU_INV_PASID_FLAGS_PASID; + + piotlb_info.domain_id = domain_id; + piotlb_info.pasid = pasid; + piotlb_info.cache_info = cache_info; + + vtd_iommu_lock(s); + /* + * Here loops all the vtd_pasid_as instances in s->vtd_pasid_as + * to find out the affected devices since piotlb invalidation + * should check pasid cache per architecture point of view. + */ + g_hash_table_foreach(s->vtd_pasid_as, + vtd_flush_pasid_iotlb, &piotlb_info); + vtd_iommu_unlock(s); + g_free(cache_info); } static void vtd_piotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id, uint32_t pasid, hwaddr addr, uint8_t am, bool ih) { + VTDPIOTLBInvInfo piotlb_info; + struct iommu_cache_invalidate_info *cache_info; + + cache_info = g_malloc0(sizeof(*cache_info)); + + cache_info->argsz = sizeof(*cache_info); + cache_info->version = IOMMU_CACHE_INVALIDATE_INFO_VERSION_1; + cache_info->cache = IOMMU_CACHE_INV_TYPE_IOTLB; + cache_info->granularity = IOMMU_INV_GRANU_ADDR; + cache_info->granu.addr_info.flags = IOMMU_INV_ADDR_FLAGS_PASID; + cache_info->granu.addr_info.flags |= ih ? IOMMU_INV_ADDR_FLAGS_LEAF : 0; + cache_info->granu.addr_info.pasid = pasid; + cache_info->granu.addr_info.addr = addr; + cache_info->granu.addr_info.granule_size = 1 << (12 + am); + cache_info->granu.addr_info.nb_granules = 1; + + piotlb_info.domain_id = domain_id; + piotlb_info.pasid = pasid; + piotlb_info.cache_info = cache_info; + + vtd_iommu_lock(s); + /* + * Here loops all the vtd_pasid_as instances in s->vtd_pasid_as + * to find out the affected devices since piotlb invalidation + * should check pasid cache per architecture point of view. + */ + g_hash_table_foreach(s->vtd_pasid_as, + vtd_flush_pasid_iotlb, &piotlb_info); + vtd_iommu_unlock(s); + g_free(cache_info); } static bool vtd_process_piotlb_desc(IntelIOMMUState *s, diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 24b5f934c3..7fbdd53b60 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -576,6 +576,13 @@ struct VTDPASIDCacheInfo { }; typedef struct VTDPASIDCacheInfo VTDPASIDCacheInfo; +struct VTDPIOTLBInvInfo { + uint16_t domain_id; + uint32_t pasid; + struct iommu_cache_invalidate_info *cache_info; +}; +typedef struct VTDPIOTLBInvInfo VTDPIOTLBInvInfo; + /* PASID Table Related Definitions */ #define VTD_PASID_DIR_BASE_ADDR_MASK (~0xfffULL) #define VTD_PASID_TABLE_BASE_ADDR_MASK (~0xfffULL) From patchwork Tue Mar 2 20:38:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446030 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcZs3f8Dz9sS8 for ; Tue, 2 Mar 2021 23:56:37 +1100 (AEDT) Received: from localhost ([::1]:51990 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4Zn-0001NW-Fx for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:56:35 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33528) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4LH-0000VV-4I for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:35 -0500 Received: from mga05.intel.com ([192.55.52.43]:62538) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4LF-0002xO-85 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:34 -0500 IronPort-SDR: YKHwsa4gVepuxZrrg5AiXey6LfRWjM+L3hjCLkOV6jmA73UVZHMCf8+cqISPpuvbN9bzs+S/st GLBxKYHbNA5A== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="271803331" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="271803331" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:41:23 -0800 IronPort-SDR: ScT5sm/6NlwtkAffhS8Fnb+OsqQ/2TYo2eCnZYTV3e2kZrAGUJpB1NsS3vGp5lpQJsFIvP54I+ aeVE+xUc3zNQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473191" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:41:17 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 24/25] intel_iommu: process PASID-based Device-TLB invalidation Date: Wed, 3 Mar 2021 04:38:26 +0800 Message-Id: <20210302203827.437645-25-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.43; envelope-from=yi.l.liu@intel.com; helo=mga05.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch adds an empty handling for PASID-based Device-TLB invalidation. For now it is enough as it is not necessary to propagate it to host for passthru device and also there is no emulated device has device tlb. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Reviewed-by: Peter Xu Signed-off-by: Liu Yi L --- hw/i386/intel_iommu.c | 18 ++++++++++++++++++ hw/i386/intel_iommu_internal.h | 1 + 2 files changed, 19 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 915db7ad1f..932c235f37 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3258,6 +3258,17 @@ static bool vtd_process_inv_iec_desc(IntelIOMMUState *s, return true; } +static bool vtd_process_device_piotlb_desc(IntelIOMMUState *s, + VTDInvDesc *inv_desc) +{ + /* + * no need to handle it for passthru device, for emulated + * devices with device tlb, it may be required, but for now, + * return is enough + */ + return true; +} + static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { @@ -3380,6 +3391,13 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) } break; + case VTD_INV_DESC_DEV_PIOTLB: + trace_vtd_inv_desc("device-piotlb", inv_desc.hi, inv_desc.lo); + if (!vtd_process_device_piotlb_desc(s, &inv_desc)) { + return false; + } + break; + case VTD_INV_DESC_DEVICE: trace_vtd_inv_desc("device", inv_desc.hi, inv_desc.lo); if (!vtd_process_device_iotlb_desc(s, &inv_desc)) { diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 7fbdd53b60..be29f3672b 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -405,6 +405,7 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */ #define VTD_INV_DESC_PIOTLB 0x6 /* PASID-IOTLB Invalidate Desc */ #define VTD_INV_DESC_PC 0x7 /* PASID-cache Invalidate Desc */ +#define VTD_INV_DESC_DEV_PIOTLB 0x8 /* PASID-based-DIOTLB inv_desc*/ #define VTD_INV_DESC_NONE 0 /* Not an Invalidate Descriptor */ /* Masks for Invalidation Wait Descriptor*/ From patchwork Tue Mar 2 20:38:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 1446026 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DqcWB37C5z9sS8 for ; Tue, 2 Mar 2021 23:53:26 +1100 (AEDT) Received: from localhost ([::1]:42500 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lH4Wi-0005mO-EH for incoming@patchwork.ozlabs.org; Tue, 02 Mar 2021 07:53:24 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:33538) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4LI-0000ay-P2 for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:36 -0500 Received: from mga05.intel.com ([192.55.52.43]:62540) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lH4LG-0002xU-Ib for qemu-devel@nongnu.org; Tue, 02 Mar 2021 07:41:36 -0500 IronPort-SDR: oTx39cIaHKtAJVMdwuuc9GIzQ/4GjjH+AoBz2weMejnmb8BnM1M6ePT/KBHrAasYJ93cltXuot 3/4EOb6sQGag== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="271803345" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="271803345" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Mar 2021 04:41:27 -0800 IronPort-SDR: lFKUWn0rSqPG/euKKza+izIe7XKhlv0wFHqvmsj3eGwcTpkMTEsRw00qzDMc5AIVcDxylYxx6I MebPpodK9JzA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427473197" Received: from yiliu-dev.bj.intel.com (HELO dual-ub.bj.intel.com) ([10.238.156.135]) by fmsmga004.fm.intel.com with ESMTP; 02 Mar 2021 04:41:23 -0800 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com, jasowang@redhat.com Subject: [RFC v11 25/25] intel_iommu: modify x-scalable-mode to be string option Date: Wed, 3 Mar 2021 04:38:27 +0800 Message-Id: <20210302203827.437645-26-yi.l.liu@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210302203827.437645-1-yi.l.liu@intel.com> References: <20210302203827.437645-1-yi.l.liu@intel.com> MIME-Version: 1.0 Received-SPF: pass client-ip=192.55.52.43; envelope-from=yi.l.liu@intel.com; helo=mga05.intel.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DATE_IN_FUTURE_06_12=1.947, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe@linaro.org, kevin.tian@intel.com, yi.l.liu@intel.com, Yi Sun , Eduardo Habkost , kvm@vger.kernel.org, mst@redhat.com, jun.j.tian@intel.com, eric.auger@redhat.com, yi.y.sun@intel.com, Jacob Pan , pbonzini@redhat.com, Lingshan.Zhu@intel.com, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Intel VT-d 3.0 introduces scalable mode, and it has a bunch of capabilities related to scalable mode translation, thus there are multiple combinations. While this vIOMMU implementation wants simplify it for user by providing typical combinations. User could config it by "x-scalable-mode" option. The usage is as below: "-device intel-iommu,x-scalable-mode=["legacy"|"modern"|"off"]" - "legacy": gives support for SL page table - "modern": gives support for FL page table, pasid, virtual command - "off": no scalable mode support - if not configured, means no scalable mode support, if not proper configured, will throw error Note: this patch is supposed to be merged when the whole vSVA patch series were merged. Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Yi Sun Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Reviewed-by: Peter Xu Signed-off-by: Liu Yi L Signed-off-by: Yi Sun --- rfcv10 -> rfcv11: *) this series uses /dev/ioasid for PASID allocation/free. In this patch, /dev/ioasid is opened it when deciding config. rfcv5 (v2) -> rfcv6: *) reports want_nested to VFIO; *) assert iommu_set/unset_iommu_context() if vIOMMU is not scalable modern. --- hw/i386/intel_iommu.c | 74 ++++++++++++++++++++++++++++++++-- hw/i386/intel_iommu_internal.h | 3 ++ include/hw/i386/intel_iommu.h | 2 + 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 932c235f37..c7322357d3 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4085,7 +4085,7 @@ static Property vtd_properties[] = { DEFINE_PROP_UINT8("aw-bits", IntelIOMMUState, aw_bits, VTD_HOST_ADDRESS_WIDTH), DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE), - DEFINE_PROP_BOOL("x-scalable-mode", IntelIOMMUState, scalable_mode, FALSE), + DEFINE_PROP_STRING("x-scalable-mode", IntelIOMMUState, scalable_mode_str), DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true), DEFINE_PROP_END_OF_LIST(), }; @@ -4454,6 +4454,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) static int vtd_dev_get_iommu_attr(PCIBus *bus, void *opaque, int32_t devfn, IOMMUAttr attr, void *data) { + IntelIOMMUState *s = opaque; int ret = 0; assert(0 <= devfn && devfn < PCI_DEVFN_MAX); @@ -4463,8 +4464,7 @@ static int vtd_dev_get_iommu_attr(PCIBus *bus, void *opaque, int32_t devfn, { bool *pdata = data; - /* return false until vSVA is ready */ - *pdata = false; + *pdata = s->scalable_modern ? true : false; break; } default: @@ -4558,6 +4558,8 @@ static int vtd_dev_set_iommu_context(PCIBus *bus, void *opaque, VTDHostIOMMUContext *vtd_dev_icx; assert(0 <= devfn && devfn < PCI_DEVFN_MAX); + /* only modern scalable supports unset_ioimmu_context */ + assert(s->scalable_modern); vtd_bus = vtd_find_add_bus(s, bus); @@ -4592,6 +4594,8 @@ static void vtd_dev_unset_iommu_context(PCIBus *bus, void *opaque, int devfn) VTDHostIOMMUContext *vtd_dev_icx; assert(0 <= devfn && devfn < PCI_DEVFN_MAX); + /* only modern scalable supports set_ioimmu_context */ + assert(s->scalable_modern); vtd_bus = vtd_find_add_bus(s, bus); @@ -4820,8 +4824,13 @@ static void vtd_init(IntelIOMMUState *s) } /* TODO: read cap/ecap from host to decide which cap to be exposed. */ - if (s->scalable_mode) { + if (s->scalable_mode && !s->scalable_modern) { s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_SRS | VTD_ECAP_SLTS; + } else if (s->scalable_mode && s->scalable_modern) { + s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_SRS | VTD_ECAP_PASID | + VTD_ECAP_FLTS | VTD_ECAP_PSS(VTD_PASID_SS) | + VTD_ECAP_VCS; + s->vccap |= VTD_VCCAP_PAS; } if (!s->cap_finalized) { @@ -4962,6 +4971,63 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) return false; } + if (s->scalable_mode_str && + (strcmp(s->scalable_mode_str, "off") && + strcmp(s->scalable_mode_str, "modern") && + strcmp(s->scalable_mode_str, "legacy"))) { + error_setg(errp, "Invalid x-scalable-mode config," + "Please use \"modern\", \"legacy\" or \"off\""); + return false; + } + + if (s->scalable_mode_str && + !strcmp(s->scalable_mode_str, "legacy")) { + s->scalable_mode = true; + s->scalable_modern = false; + } else if (s->scalable_mode_str && + !strcmp(s->scalable_mode_str, "modern")) { + if (ioasid_fd < 0) { + int fd, version; + struct ioasid_info info; + + fd = qemu_open_old("/dev/ioasid", O_RDWR); + if (fd < 0) { + error_setg(errp, "Failed to open /dev/ioasid, %m"); + return false; + } + + version = ioctl(fd, IOASID_GET_API_VERSION); + if (version != IOASID_API_VERSION) { + error_setg(errp, "supported ioasid version: %d, " + "reported version: %d", IOASID_API_VERSION, version); + return false; + } + + memset(&info, 0x0, sizeof(info)); + info.argsz = sizeof(info); + if (ioctl(fd, IOASID_GET_INFO, &info)) { + error_setg(errp, "Failed to get ioasid info, %m"); + return false; + } + + if ((VTD_PASID_SS + 1) > info.ioasid_bits) { + error_setg(errp, "supported pasid bits: %u, reported pasid " + "bits: %u", VTD_PASID_SS + 1, info.ioasid_bits); + return false; + } + + ioasid_fd = fd; + ioasid_bits = info.ioasid_bits; + } + s->ioasid_fd = ioasid_fd; + s->ioasid_bits = ioasid_bits; + s->scalable_mode = true; + s->scalable_modern = true; + } else { + s->scalable_mode = false; + s->scalable_modern = false; + } + return true; } diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index be29f3672b..3587137915 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -197,7 +197,9 @@ #define VTD_ECAP_MHMV (15ULL << 20) #define VTD_ECAP_SRS (1ULL << 31) #define VTD_ECAP_SMTS (1ULL << 43) +#define VTD_ECAP_VCS (1ULL << 44) #define VTD_ECAP_SLTS (1ULL << 46) +#define VTD_ECAP_FLTS (1ULL << 47) /* 1st level related caps */ #define VTD_CAP_FL1GP (1ULL << 56) @@ -209,6 +211,7 @@ #define VTD_ECAP_PSS(val) (((val) & 0x1fULL) << 35) #define VTD_ECAP_PASID (1ULL << 40) +#define VTD_PASID_SS (19) #define VTD_GET_PSS(val) (((val) >> 35) & 0x1f) #define VTD_ECAP_PSS_MASK (0x1fULL << 35) diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 10dabff6b5..4aac1fa912 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -262,6 +262,8 @@ struct IntelIOMMUState { bool caching_mode; /* RO - is cap CM enabled? */ bool scalable_mode; /* RO - is Scalable Mode supported? */ + char *scalable_mode_str; /* RO - admin's Scalable Mode config */ + bool scalable_modern; /* RO - is modern SM supported? */ dma_addr_t root; /* Current root table pointer */ bool root_scalable; /* Type of root table (scalable or not) */