From patchwork Sun Mar 22 12:35:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451733 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 251A16CA for ; Sun, 22 Mar 2020 12:31:45 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 0391820724 for ; Sun, 22 Mar 2020 12:31:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0391820724 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45920 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzlY-0002Tf-0E for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:31:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47824) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkf-0000n6-Tb for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkc-0003qv-VM for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:48 -0400 Received: from mga11.intel.com ([192.55.52.93]:51464) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkc-0003ok-3f for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:46 -0400 IronPort-SDR: PZMt++oVfTA/NlQYoWUa8VTxjyVrrv/qHqpc7viF+KkZtu8oZoBzACTQS+PV7EbINAA+0aZfMt S/M+X3D2NyUQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: htDY/owjdKMDnf6H8wwZhdcxULwRXP+FHsPWdgWI8nSmhCEYFBXpTgRTVHQgrHIXh25HyvV59a ioB6EBufEIWg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664353" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:37 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 01/22] scripts/update-linux-headers: Import iommu.h Date: Sun, 22 Mar 2020 05:35:58 -0700 Message-Id: <1584880579-12178-2-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 192.55.52.93 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 --- 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 29c27f4..5b64ee3 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -141,7 +141,7 @@ done rm -rf "$output/linux-headers/linux" mkdir -p "$output/linux-headers/linux" -for header in kvm.h vfio.h vfio_ccw.h vhost.h \ +for header in kvm.h vfio.h vfio_ccw.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 Sun Mar 22 12:35:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451743 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E3CD31731 for ; Sun, 22 Mar 2020 12:33:44 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id AFD4B20724 for ; Sun, 22 Mar 2020 12:33:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org AFD4B20724 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45948 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFznT-0005og-Ov for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:33:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47914) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkn-0000yC-VT for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkk-0003tI-Hm for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:57 -0400 Received: from mga11.intel.com ([192.55.52.93]:51489) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkf-0003r7-9E for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:51 -0400 IronPort-SDR: 4I+qsm8TnNSdmgNxOJxXe4Df7X2veffjegQSES0Tm0u5HJef4v4PgxqvzFcHgr7w9PKo3QkoA9 28dsZuxsALFA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: sHQa3+iz5MjbbqGtfYdvOJE8Qj9O/kWCJertHsh/VkqCosi2PMC4ZL4IoQPv4EVfKN6HhUZ26R /w56lzqmKK2w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664356" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:37 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 02/22] header file update VFIO/IOMMU vSVA APIs Date: Sun, 22 Mar 2020 05:35:59 -0700 Message-Id: <1584880579-12178-3-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 192.55.52.93 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" The kernel uapi/linux/iommu.h header file includes the extensions for vSVA support. e.g. bind gpasid, iommu fault report related user structures and etc. 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 Cc: Cornelia Huck Cc: Paolo Bonzini Signed-off-by: Liu Yi L --- linux-headers/linux/iommu.h | 378 ++++++++++++++++++++++++++++++++++++++++++++ linux-headers/linux/vfio.h | 127 +++++++++++++++ 2 files changed, 505 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 0000000..9025496 --- /dev/null +++ b/linux-headers/linux/iommu.h @@ -0,0 +1,378 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * IOMMU user API definitions + */ + +#ifndef _IOMMU_H +#define _IOMMU_H + +#include + +/** + * Current version of the IOMMU user API. This is intended for query + * between user and kernel to determine compatible data structures. + * + * UAPI version can be bumped up with the following rules: + * 1. All data structures passed between user and kernel space share + * the same version number. i.e. any extension to any structure + * results in version number increment. + * + * 2. Data structures are open to extension but closed to modification. + * Extension should leverage the padding bytes first where a new + * flag bit is required to indicate the validity of each new member. + * The above rule for padding bytes also applies to adding new union + * members. + * After padding bytes are exhausted, new fields must be added at the + * end of each data structure with 64bit alignment. Flag bits can be + * added without size change but existing ones cannot be altered. + * + * 3. Versions are backward compatible. + * + * 4. Version to size lookup is supported by kernel internal API for each + * API function type. @version is mandatory for new data structures + * and must be at the beginning with type of __u32. + */ +#define IOMMU_UAPI_VERSION 1 +static __inline__ int iommu_get_uapi_version(void) +{ + return IOMMU_UAPI_VERSION; +} + +/* + * Supported UAPI features that can be reported to user space. + * These types represent the capability available in the kernel. + * + * REVISIT: UAPI version also implies the capabilities. Should we + * report them explicitly? + */ +enum IOMMU_UAPI_DATA_TYPES { + IOMMU_UAPI_BIND_GPASID, + IOMMU_UAPI_CACHE_INVAL, + IOMMU_UAPI_PAGE_RESP, + NR_IOMMU_UAPI_TYPE, +}; + +#define IOMMU_UAPI_CAP_MASK ((1 << IOMMU_UAPI_BIND_GPASID) | \ + (1 << IOMMU_UAPI_CACHE_INVAL) | \ + (1 << IOMMU_UAPI_PAGE_RESP)) + +#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) + * @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) + __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 + * @version: IOMMU_UAPI_VERSION + * @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 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 + * @version: IOMMU_UAPI_VERSION + * @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 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[2]; + union { + struct iommu_inv_pasid_info pasid_info; + struct iommu_inv_addr_info addr_info; + }; +}; + +/** + * 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 */ + __u64 flags; + __u32 pat; + __u32 emt; +}; +#define IOMMU_SVA_VTD_GPASID_EMT_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 + * @version: IOMMU_UAPI_VERSION + * @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) + * @dummy Reserve space for vendor specific data in the union. New + * members added to the union cannot exceed the size of dummy. + * The fixed size union is needed to allow further expansion + * after the end of the union while still maintain backward + * compatibility. + * @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 version; +#define IOMMU_PASID_FORMAT_INTEL_VTD 1 + __u32 format; +#define IOMMU_SVA_GPASID_VAL (1 << 0) /* guest PASID valid */ + __u64 flags; + __u64 gpgd; + __u64 hpasid; + __u64 gpasid; + __u32 addr_width; + __u8 padding[12]; + /* Vendor specific data */ + union { + __u8 dummy[128]; + struct iommu_gpasid_bind_data_vtd vtd; + }; +}; + +#endif /* _IOMMU_H */ diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index fb10370..29d0071 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 @@ -47,6 +48,15 @@ #define VFIO_NOIOMMU_IOMMU 8 /* + * Hardware IOMMUs with two-stage translation capability give userspace + * the ownership of stage-1 translation structures (e.g. page tables). + * VFIO exposes the two-stage IOMMU programming capability to userspace + * based on the IOMMU UAPIs. Therefore user of VFIO_TYPE1_NESTING should + * check the IOMMU UAPI version compatibility. + */ +#define VFIO_NESTING_IOMMU_UAPI 9 + +/* * The IOCTL interface is designed for extensibility by embedding the * structure length (argsz) and flags into structures passed between * kernel and userspace. We therefore use the _IO() macro for these @@ -748,6 +758,15 @@ struct vfio_iommu_type1_info_cap_iova_range { struct vfio_iova_range iova_ranges[]; }; +#define VFIO_IOMMU_TYPE1_INFO_CAP_NESTING 2 + +struct vfio_iommu_type1_info_cap_nesting { + struct vfio_info_cap_header header; +#define VFIO_IOMMU_PASID_REQS (1 << 0) + __u32 nesting_capabilities; + __u32 stage1_formats; +}; + #define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12) /** @@ -794,6 +813,114 @@ struct vfio_iommu_type1_dma_unmap { #define VFIO_IOMMU_ENABLE _IO(VFIO_TYPE, VFIO_BASE + 15) #define VFIO_IOMMU_DISABLE _IO(VFIO_TYPE, VFIO_BASE + 16) +/* + * PASID (Process Address Space ID) is a PCIe concept which + * has been extended to support DMA isolation in fine-grain. + * With device assigned to user space (e.g. VMs), PASID alloc + * and free need to be system wide. This structure defines + * the info for pasid alloc/free between user space and kernel + * space. + * + * @flag=VFIO_IOMMU_PASID_ALLOC, refer to the @alloc_pasid + * @flag=VFIO_IOMMU_PASID_FREE, refer to @free_pasid + */ +struct vfio_iommu_type1_pasid_request { + __u32 argsz; +#define VFIO_IOMMU_PASID_ALLOC (1 << 0) +#define VFIO_IOMMU_PASID_FREE (1 << 1) + __u32 flags; + union { + struct { + __u32 min; + __u32 max; + __u32 result; + } alloc_pasid; + __u32 free_pasid; + }; +}; + +#define VFIO_PASID_REQUEST_MASK (VFIO_IOMMU_PASID_ALLOC | \ + VFIO_IOMMU_PASID_FREE) + +/** + * VFIO_IOMMU_PASID_REQUEST - _IOWR(VFIO_TYPE, VFIO_BASE + 22, + * struct vfio_iommu_type1_pasid_request) + * + * Availability of this feature depends on PASID support in the device, + * its bus, the underlying IOMMU and the CPU architecture. In VFIO, it + * is available after VFIO_SET_IOMMU. + * + * returns: 0 on success, -errno on failure. + */ +#define VFIO_IOMMU_PASID_REQUEST _IO(VFIO_TYPE, VFIO_BASE + 22) + +/** + * Supported flags: + * - VFIO_IOMMU_BIND_GUEST_PGTBL: bind guest page tables to host for + * nesting type IOMMUs. In @data field It takes struct + * iommu_gpasid_bind_data. + * - VFIO_IOMMU_UNBIND_GUEST_PGTBL: undo a bind guest page table operation + * invoked by VFIO_IOMMU_BIND_GUEST_PGTBL. + * + */ +struct vfio_iommu_type1_bind { + __u32 argsz; + __u32 flags; +#define VFIO_IOMMU_BIND_GUEST_PGTBL (1 << 0) +#define VFIO_IOMMU_UNBIND_GUEST_PGTBL (1 << 1) + __u8 data[]; +}; + +#define VFIO_IOMMU_BIND_MASK (VFIO_IOMMU_BIND_GUEST_PGTBL | \ + VFIO_IOMMU_UNBIND_GUEST_PGTBL) + +/** + * VFIO_IOMMU_BIND - _IOW(VFIO_TYPE, VFIO_BASE + 23, + * struct vfio_iommu_type1_bind) + * + * Manage address spaces of devices in this container. Initially a TYPE1 + * container can only have one address space, managed with + * VFIO_IOMMU_MAP/UNMAP_DMA. + * + * An IOMMU of type VFIO_TYPE1_NESTING_IOMMU can be managed by both MAP/UNMAP + * and BIND ioctls at the same time. MAP/UNMAP acts on the stage-2 (host) page + * tables, and BIND manages the stage-1 (guest) page tables. Other types of + * IOMMU may allow MAP/UNMAP and BIND to coexist, where MAP/UNMAP controls + * the traffics only require single stage translation while BIND controls the + * traffics require nesting translation. But this depends on the underlying + * IOMMU architecture and isn't guaranteed. Example of this is the guest SVA + * traffics, such traffics need nesting translation to gain gVA->gPA and then + * gPA->hPA translation. + * + * Availability of this feature depends on the device, its bus, the underlying + * IOMMU and the CPU architecture. + * + * returns: 0 on success, -errno on failure. + */ +#define VFIO_IOMMU_BIND _IO(VFIO_TYPE, VFIO_BASE + 23) + +/** + * VFIO_IOMMU_CACHE_INVALIDATE - _IOW(VFIO_TYPE, VFIO_BASE + 24, + * struct vfio_iommu_type1_cache_invalidate) + * + * Propagate guest IOMMU cache invalidation to the host. The cache + * invalidation information is conveyed by @cache_info, the content + * format would be structures defined in uapi/linux/iommu.h. User + * should be aware of that the struct iommu_cache_invalidate_info + * has a @version field, vfio needs to parse this field before getting + * data from userspace. + * + * Availability of this IOCTL is after VFIO_SET_IOMMU. + * + * returns: 0 on success, -errno on failure. + */ +struct vfio_iommu_type1_cache_invalidate { + __u32 argsz; + __u32 flags; + struct iommu_cache_invalidate_info cache_info; +}; +#define VFIO_IOMMU_CACHE_INVALIDATE _IO(VFIO_TYPE, VFIO_BASE + 24) + /* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */ /* From patchwork Sun Mar 22 12:36:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451751 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2A67E6CA for ; Sun, 22 Mar 2020 12:35:50 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id F3F1B206F8 for ; Sun, 22 Mar 2020 12:35:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org F3F1B206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45986 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzpV-00013p-03 for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:35:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47876) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkm-0000ws-H6 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkk-0003tW-P3 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:56 -0400 Received: from mga11.intel.com ([192.55.52.93]:51464) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzki-0003ok-5z for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:53 -0400 IronPort-SDR: ZbUI3boWbTKXftFvoGoTnV4Wqw0Wb0F/m+TZQvQeg4aoNAxqB7xqshagD3kNsJywFcyNts+T5c CrK944c+Dl3g== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: zkcwltI3q2jMqH9FHuy8GB68A4RpIANzpHw3JzPnrpLAXICeuYiJd4PLP0rFGCrJ1a2DVX3jZJ M71QnzUtKyMA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664358" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:37 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 03/22] vfio: check VFIO_TYPE1_NESTING_IOMMU support Date: Sun, 22 Mar 2020 05:36:00 -0700 Message-Id: <1584880579-12178-4-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 192.55.52.93 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 version. 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: Yi Sun --- hw/vfio/common.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 0b3593b..c276732 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1157,12 +1157,21 @@ static void vfio_put_address_space(VFIOAddressSpace *space) static int vfio_get_iommu_type(VFIOContainer *container, 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, version; for (i = 0; i < ARRAY_SIZE(iommu_types); i++) { if (ioctl(container->fd, VFIO_CHECK_EXTENSION, iommu_types[i])) { + if (iommu_types[i] == VFIO_TYPE1_NESTING_IOMMU) { + version = ioctl(container->fd, VFIO_CHECK_EXTENSION, + VFIO_NESTING_IOMMU_UAPI); + if (version < IOMMU_UAPI_VERSION) { + info_report("IOMMU UAPI incompatible for nesting"); + continue; + } + } return iommu_types[i]; } } @@ -1278,6 +1287,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, } switch (container->iommu_type) { + case VFIO_TYPE1_NESTING_IOMMU: case VFIO_TYPE1v2_IOMMU: case VFIO_TYPE1_IOMMU: { From patchwork Sun Mar 22 12:36:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451779 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DDB266CA for ; Sun, 22 Mar 2020 12:44:26 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id BC2E220722 for ; Sun, 22 Mar 2020 12:44:26 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BC2E220722 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46126 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzxp-0005mE-TK for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:44:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:48144) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzlB-0001eC-S7 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzl9-00043O-Lj for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:21 -0400 Received: from mga02.intel.com ([134.134.136.20]:41752) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzl9-0003r4-Df for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:19 -0400 IronPort-SDR: hQ9K/ZHcHk4c0t9jaBS9QfBQCZPMS9cswTm7lZ+jt1+giq14cOFJTuRkQEIqE2qLu5fA0vfbjC 7GPxRgqHQIvA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: TqXkHuoecRLM8tYDPnWDxMLZc0L8bWNqklgT0ZrYNnKMiRMagSodASF2uuPlwPcIP+kAY0Q2wi a++quWZQ2xKQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664361" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:37 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 04/22] hw/iommu: introduce HostIOMMUContext Date: Sun, 22 Mar 2020 05:36:01 -0700 Message-Id: <1584880579-12178-5-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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. Thus the major connection between VFIO and vIOMMU are MAP/UNMAP. However, with the dual stage DMA translation support, there are more interactions between vIOMMU and VFIO as below: 1) PASID allocation (allow host to intercept in PASID allocation) 2) bind stage-1 translation structures to host 3) propagate stage-1 cache invalidation to host 4) 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 stand for hardware IOMMU w/ dual stage DMA address translation capability. And introduces HostIOMMUContextClass to provide methods for vIOMMU emulators to propagate dual-stage translation related requests to host. As a beginning, PASID allocation/free are defined to propagate PASID allocation/free requests to host which is helpful for the vendors who manage PASID in system-wide. In future, there will be more operations like bind_stage1_pgtbl, flush_stage1_cache and etc. 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/Makefile.objs | 1 + hw/iommu/Makefile.objs | 1 + hw/iommu/host_iommu_context.c | 112 ++++++++++++++++++++++++++++++++++ include/hw/iommu/host_iommu_context.h | 75 +++++++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 hw/iommu/Makefile.objs create mode 100644 hw/iommu/host_iommu_context.c create mode 100644 include/hw/iommu/host_iommu_context.h diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 660e2b4..cab83fe 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -40,6 +40,7 @@ devices-dirs-$(CONFIG_MEM_DEVICE) += mem/ devices-dirs-$(CONFIG_NUBUS) += nubus/ devices-dirs-y += semihosting/ devices-dirs-y += smbios/ +devices-dirs-y += iommu/ endif common-obj-y += $(devices-dirs-y) diff --git a/hw/iommu/Makefile.objs b/hw/iommu/Makefile.objs new file mode 100644 index 0000000..e6eed4e --- /dev/null +++ b/hw/iommu/Makefile.objs @@ -0,0 +1 @@ +obj-y += host_iommu_context.o diff --git a/hw/iommu/host_iommu_context.c b/hw/iommu/host_iommu_context.c new file mode 100644 index 0000000..af61899 --- /dev/null +++ b/hw/iommu/host_iommu_context.c @@ -0,0 +1,112 @@ +/* + * 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_pasid_alloc(HostIOMMUContext *host_icx, uint32_t min, + uint32_t max, uint32_t *pasid) +{ + HostIOMMUContextClass *hicxc; + + if (!host_icx) { + return -EINVAL; + } + + hicxc = HOST_IOMMU_CONTEXT_GET_CLASS(host_icx); + + if (!hicxc) { + return -EINVAL; + } + + if (!(host_icx->flags & HOST_IOMMU_PASID_REQUEST) || + !hicxc->pasid_alloc) { + return -EINVAL; + } + + return hicxc->pasid_alloc(host_icx, min, max, pasid); +} + +int host_iommu_ctx_pasid_free(HostIOMMUContext *host_icx, uint32_t pasid) +{ + HostIOMMUContextClass *hicxc; + + if (!host_icx) { + return -EINVAL; + } + + hicxc = HOST_IOMMU_CONTEXT_GET_CLASS(host_icx); + if (!hicxc) { + return -EINVAL; + } + + if (!(host_icx->flags & HOST_IOMMU_PASID_REQUEST) || + !hicxc->pasid_free) { + return -EINVAL; + } + + return hicxc->pasid_free(host_icx, pasid); +} + +void host_iommu_ctx_init(void *_host_icx, size_t instance_size, + const char *mrtypename, + uint64_t flags) +{ + HostIOMMUContext *host_icx; + + object_initialize(_host_icx, instance_size, mrtypename); + host_icx = HOST_IOMMU_CONTEXT(_host_icx); + host_icx->flags = flags; + host_icx->initialized = true; +} + +void host_iommu_ctx_destroy(HostIOMMUContext *host_icx) +{ + host_icx->flags = 0x0; + host_icx->initialized = false; +} + +static void host_icx_init_fn(Object *obj) +{ + HostIOMMUContext *host_icx = HOST_IOMMU_CONTEXT(obj); + + host_icx->flags = 0x0; + host_icx->initialized = false; +} + +static const TypeInfo host_iommu_context_info = { + .parent = TYPE_OBJECT, + .name = TYPE_HOST_IOMMU_CONTEXT, + .class_size = sizeof(HostIOMMUContextClass), + .instance_size = sizeof(HostIOMMUContext), + .instance_init = host_icx_init_fn, + .abstract = true, +}; + +static void host_icx_register_types(void) +{ + type_register_static(&host_iommu_context_info); +} + +type_init(host_icx_register_types) diff --git a/include/hw/iommu/host_iommu_context.h b/include/hw/iommu/host_iommu_context.h new file mode 100644 index 0000000..cfbf5ac --- /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; + + /* Allocate pasid from HostIOMMUContext (a.k.a. host software) */ + int (*pasid_alloc)(HostIOMMUContext *host_icx, + uint32_t min, + uint32_t max, + uint32_t *pasid); + /* Reclaim pasid from HostIOMMUContext (a.k.a. host software) */ + int (*pasid_free)(HostIOMMUContext *host_icx, + uint32_t pasid); +} HostIOMMUContextClass; + +/* + * This is an abstraction of host IOMMU with dual-stage capability + */ +struct HostIOMMUContext { + Object parent_obj; +#define HOST_IOMMU_PASID_REQUEST (1ULL << 0) + uint64_t flags; + bool initialized; +}; + +int host_iommu_ctx_pasid_alloc(HostIOMMUContext *host_icx, uint32_t min, + uint32_t max, uint32_t *pasid); +int host_iommu_ctx_pasid_free(HostIOMMUContext *host_icx, uint32_t pasid); + +void host_iommu_ctx_init(void *_host_icx, size_t instance_size, + const char *mrtypename, + uint64_t flags); +void host_iommu_ctx_destroy(HostIOMMUContext *host_icx); + +#endif From patchwork Sun Mar 22 12:36:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451737 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3BAE11731 for ; Sun, 22 Mar 2020 12:31:50 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 096AE20724 for ; Sun, 22 Mar 2020 12:31:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 096AE20724 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45924 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzld-0002iR-3j for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:31:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47848) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkk-0000wR-Hf for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkc-0003qs-V7 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:51 -0400 Received: from mga02.intel.com ([134.134.136.20]:41735) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkc-0003ol-2T for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:46 -0400 IronPort-SDR: qgnKGvk6kNcFu14w8zPOK8s2lCwRbxHfGIlim6fjtY4LQVPS0IQp1/g728zmmfNnvjKNNovfyU 3hRhZwwicqHQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: RnMDUl8jxtIMndnvMdYhydtk76z8Tw/dW3cx2VTPM+pNwbgBcduCdywH/+LPU2xfV07e+JQWX/ 7OLtagRIli+A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664365" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:37 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 05/22] hw/pci: modify pci_setup_iommu() to set PCIIOMMUOps Date: Sun, 22 Mar 2020 05:36:02 -0700 Message-Id: <1584880579-12178-6-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 --- 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 | 12 +++++++----- 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, 90 insertions(+), 24 deletions(-) diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 1795e2f..f271de1 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 e13a5f4..447146e 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -343,6 +343,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; @@ -437,7 +441,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 2b1b38c..3da4f84 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 b1175e5..5fec30e 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1451,6 +1451,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, @@ -1577,7 +1581,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", errp); 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 df7ad25..4b22910 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3729,6 +3729,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); @@ -3840,7 +3844,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 dd24551..4c6338a 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -645,6 +645,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); @@ -686,7 +690,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_set_parent_bus(DEVICE(&s->root), BUS(pci->bus)); qdev_init_nofail(DEVICE(&s->root)); diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 74618fa..ecfe627 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -961,6 +961,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); @@ -1059,7 +1063,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 23cf093..04e95e3 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1148,6 +1148,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); @@ -1205,7 +1209,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 d710727..5baf5db 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -439,6 +439,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); @@ -473,7 +477,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 1a02e9a..7c57311 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -213,6 +213,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; @@ -303,7 +307,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 2b8503b..251549b 100644 --- a/hw/pci-host/sabre.c +++ b/hw/pci-host/sabre.c @@ -112,6 +112,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) { @@ -402,7 +406,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_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, diff --git a/hw/pci/pci.c b/hw/pci/pci.c index e1ed667..aa9025c 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2644,7 +2644,7 @@ 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) { + while (iommu_bus && !iommu_bus->iommu_ops && iommu_bus->parent_dev) { PCIBus *parent_bus = pci_get_bus(iommu_bus->parent_dev); /* @@ -2683,15 +2683,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 2ee2d4f..7b17ee5 100644 --- a/hw/ppc/ppc440_pcix.c +++ b/hw/ppc/ppc440_pcix.c @@ -442,6 +442,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, +}; + /* The default pci_host_data_{read,write} functions in pci/pci_host.c * deny access to registers without bit 31 set but our clients want * this to work so we have to override these here */ @@ -487,7 +491,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), &pci_host_conf_le_ops, diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 709a527..729a1cb 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -771,6 +771,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; @@ -1950,7 +1954,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 ed8be12..c1c3aa4 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -635,6 +635,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 ind_old, ind_new; @@ -748,7 +752,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), &local_err); @@ -919,7 +923,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), errp); diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 4cee808..fefc24e 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -235,6 +235,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) { @@ -682,7 +686,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 cfedf5a..ffe192d 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 0714f57..c281057 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 Sun Mar 22 12:36:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451735 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 498B3174A for ; Sun, 22 Mar 2020 12:31:45 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 2888620724 for ; Sun, 22 Mar 2020 12:31:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2888620724 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45918 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzlY-0002Tc-9q for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:31:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47825) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkf-0000n9-U7 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkd-0003rH-G8 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:49 -0400 Received: from mga02.intel.com ([134.134.136.20]:41735) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkd-0003ol-5G for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:47 -0400 IronPort-SDR: qAvM+jhu7PkW4E/J6GnRlx01sLsDOXGLRZtV4BclMKTkcWh2SioQ1XYqCUCciNhee28foOpFXp MINCvUAL+rEw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: H29lmoJWSzJddgAHQ9mMrPiWN94pHNnpkZ2KKd6kAyKq80d5LvOvyCXTspSEDo+FvnJWyu46Ol 1eXZYJbm0lpg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664367" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:37 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 06/22] hw/pci: introduce pci_device_set/unset_iommu_context() Date: Sun, 22 Mar 2020 05:36:03 -0700 Message-Id: <1584880579-12178-7-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This patch adds pci_device_set/unset_iommu_context() to set/unset host_iommu_context for a given device. New callback is added in PCIIOMMUOps. As such, vIOMMU could make use of host IOMMU capability. e.g setup nested translation. 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 Reviewed-by: Peter Xu --- hw/pci/pci.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- include/hw/pci/pci.h | 10 ++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index aa9025c..8642ea8 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2638,7 +2638,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; @@ -2683,14 +2684,52 @@ 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_set_iommu_context(PCIDevice *dev, + HostIOMMUContext *host_icx) +{ + 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, host_icx); + } + return -ENOENT; +} + +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 ffe192d..6fca2a0 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -9,6 +9,8 @@ #include "hw/pci/pcie.h" +#include "hw/iommu/host_iommu_context.h" + extern bool pci_available; /* PCI bus */ @@ -489,9 +491,17 @@ typedef struct PCIIOMMUOps PCIIOMMUOps; struct PCIIOMMUOps { AddressSpace * (*get_address_space)(PCIBus *bus, void *opaque, int32_t devfn); + int (*set_iommu_context)(PCIBus *bus, void *opaque, + int32_t devfn, + HostIOMMUContext *host_icx); + void (*unset_iommu_context)(PCIBus *bus, void *opaque, + int32_t devfn); }; AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); +int pci_device_set_iommu_context(PCIDevice *dev, + HostIOMMUContext *host_icx); +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 Sun Mar 22 12:36:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451755 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9F9E16CA for ; Sun, 22 Mar 2020 12:35:56 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 7F16E206F8 for ; Sun, 22 Mar 2020 12:35:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7F16E206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45992 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzpb-0001Iv-JW for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:35:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47899) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkn-0000xh-Js for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkk-0003t1-H5 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:57 -0400 Received: from mga02.intel.com ([134.134.136.20]:41735) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkf-0003ol-7u for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:51 -0400 IronPort-SDR: 3LNoZZu41vdHmNlUZHlHU3OthoOgYe29fOiUSrmXzME3zUYFxo3ZvV11uH+YLYXMxB6ivLZg6q bNHMmcgG2nIw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: MxBsRZpx6VRupLILemblATcZ9jcMl5h/e5k69U5TYb82YM3CXXWkyBesqDNa9eMYVyPIgVOEeU LNVN+9t9c1eQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664370" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 07/22] intel_iommu: add set/unset_iommu_context callback Date: Sun, 22 Mar 2020 05:36:04 -0700 Message-Id: <1584880579-12178-8-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This patch adds set/unset_iommu_context() impelementation in Intel vIOMMU. For Intel platform, pass-through modules (e.g. VFIO) could set HostIOMMUContext to Intel vIOMMU emulator. 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 | 70 +++++++++++++++++++++++++++++++++++++++---- include/hw/i386/intel_iommu.h | 17 +++++++++-- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 4b22910..8d9204f 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3354,23 +3354,35 @@ 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) + PCI_DEVFN_MAX * \ + (sizeof(VTDAddressSpace *) + \ + sizeof(VTDHostIOMMUContext *))); 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) { @@ -3436,6 +3448,52 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) return vtd_dev_as; } +static int vtd_dev_set_iommu_context(PCIBus *bus, void *opaque, + int devfn, + HostIOMMUContext *host_icx) +{ + 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]; + + if (!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->host_icx = host_icx; + } + 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_iommu_unlock(s); +} + static uint64_t get_naturally_aligned_size(uint64_t start, uint64_t size, int gaw) { @@ -3731,6 +3789,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, + .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 3870052..9b4fc0a 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -64,6 +64,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 { @@ -112,10 +113,20 @@ struct VTDAddressSpace { IOVATree *iova_tree; /* Traces mapped IOVA ranges */ }; +struct VTDHostIOMMUContext { + VTDBus *vtd_bus; + uint8_t devfn; + HostIOMMUContext *host_icx; + 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 { @@ -271,6 +282,8 @@ struct IntelIOMMUState { /* * Protects IOMMU states in general. Currently it protects the * per-IOMMU IOTLB cache, and context entry cache in VTDAddressSpace. + * Protect the update/usage of HostIOMMUContext pointer cached in + * VTDBus->dev_icx array as array elements may be updated by hotplug */ QemuMutex iommu_lock; }; From patchwork Sun Mar 22 12:36:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451747 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 659656CA for ; Sun, 22 Mar 2020 12:33:51 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 442C320724 for ; Sun, 22 Mar 2020 12:33:51 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 442C320724 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45952 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzna-00064c-EI for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:33:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47877) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkm-0000wt-Hp for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkk-0003t6-H8 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:56 -0400 Received: from mga02.intel.com ([134.134.136.20]:41752) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkf-0003r4-77 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:51 -0400 IronPort-SDR: qJqkFktaKMaRU0tW1JnMJPz/f8yGOFBEIC3QSPpWvVqo8cw4EHXV3l1z0mjSCrot+8cAhCTO7g JIS8W7EtoPhw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: ZixMWGhic1XTd8cYcie6djNE42p1WRqBzLAHAstRd5jFqB5NgCboBbCgW3SOYhS9AuOpFLjZ3I 24w3QUPW8y9A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664374" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 08/22] vfio: init HostIOMMUContext per-container Date: Sun, 22 Mar 2020 05:36:05 -0700 Message-Id: <1584880579-12178-9-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" After confirming dual stage DMA translation support with kernel by checking VFIO_TYPE1_NESTING_IOMMU, VFIO inits HostIOMMUContet instance and exposes it to PCI layer. Thus vIOMMU emualtors may make use of such capability by leveraging the methods provided by HostIOMMUContext. 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 | 80 +++++++++++++++++++++++++++++++++++ hw/vfio/pci.c | 13 ++++++ include/hw/iommu/host_iommu_context.h | 3 ++ include/hw/vfio/vfio-common.h | 4 ++ 4 files changed, 100 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index c276732..e4f5f10 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1179,10 +1179,55 @@ static int vfio_get_iommu_type(VFIOContainer *container, return -EINVAL; } +static int vfio_host_icx_pasid_alloc(HostIOMMUContext *host_icx, + uint32_t min, uint32_t max, uint32_t *pasid) +{ + VFIOContainer *container = container_of(host_icx, VFIOContainer, host_icx); + struct vfio_iommu_type1_pasid_request req; + unsigned long argsz; + int ret; + + argsz = sizeof(req); + req.argsz = argsz; + req.flags = VFIO_IOMMU_PASID_ALLOC; + req.alloc_pasid.min = min; + req.alloc_pasid.max = max; + + if (ioctl(container->fd, VFIO_IOMMU_PASID_REQUEST, &req)) { + ret = -errno; + error_report("%s: %d, alloc failed", __func__, ret); + return ret; + } + *pasid = req.alloc_pasid.result; + return 0; +} + +static int vfio_host_icx_pasid_free(HostIOMMUContext *host_icx, + uint32_t pasid) +{ + VFIOContainer *container = container_of(host_icx, VFIOContainer, host_icx); + struct vfio_iommu_type1_pasid_request req; + unsigned long argsz; + int ret; + + argsz = sizeof(req); + req.argsz = argsz; + req.flags = VFIO_IOMMU_PASID_FREE; + req.free_pasid = pasid; + + if (ioctl(container->fd, VFIO_IOMMU_PASID_REQUEST, &req)) { + ret = -errno; + error_report("%s: %d, free failed", __func__, ret); + return ret; + } + return 0; +} + static int vfio_init_container(VFIOContainer *container, int group_fd, Error **errp) { int iommu_type, ret; + uint64_t flags = 0; iommu_type = vfio_get_iommu_type(container, errp); if (iommu_type < 0) { @@ -1210,6 +1255,18 @@ static int vfio_init_container(VFIOContainer *container, int group_fd, return -errno; } + if (iommu_type == VFIO_TYPE1_NESTING_IOMMU) { + /* + * TODO: config flags per host IOMMU nesting capability + * e.g. check if VFIO_TYPE1_NESTING_IOMMU supports PASID + * alloc/free + */ + host_iommu_ctx_init(&container->host_icx, + sizeof(container->host_icx), + TYPE_VFIO_HOST_IOMMU_CONTEXT, + flags); + } + container->iommu_type = iommu_type; return 0; } @@ -1456,6 +1513,7 @@ static void vfio_disconnect_container(VFIOGroup *group) } trace_vfio_disconnect_container(container->fd); + host_iommu_ctx_destroy(&container->host_icx); close(container->fd); g_free(container); @@ -1791,3 +1849,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->pasid_alloc = vfio_host_icx_pasid_alloc; + hicxc->pasid_free = vfio_host_icx_pasid_free; +} + +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/hw/vfio/pci.c b/hw/vfio/pci.c index 5e75a95..f099df3 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2717,6 +2717,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) VFIOPCIDevice *vdev = PCI_VFIO(pdev); VFIODevice *vbasedev_iter; VFIOGroup *group; + VFIOContainer *container; char *tmp, *subsys, group_path[PATH_MAX], *group_name; Error *err = NULL; ssize_t len; @@ -3028,6 +3029,11 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_register_req_notifier(vdev); vfio_setup_resetfn_quirk(vdev); + container = vdev->vbasedev.group->container; + if (container->host_icx.initialized) { + pci_device_set_iommu_context(pdev, &container->host_icx); + } + return; out_deregister: @@ -3072,9 +3078,16 @@ static void vfio_instance_finalize(Object *obj) static void vfio_exitfn(PCIDevice *pdev) { VFIOPCIDevice *vdev = PCI_VFIO(pdev); + VFIOContainer *container; vfio_unregister_req_notifier(vdev); vfio_unregister_err_notifier(vdev); + + container = vdev->vbasedev.group->container; + if (container->host_icx.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/iommu/host_iommu_context.h b/include/hw/iommu/host_iommu_context.h index cfbf5ac..5f11a4c 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 fd56420..532b78d 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -26,12 +26,15 @@ #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 #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, @@ -71,6 +74,7 @@ typedef struct VFIOContainer { MemoryListener listener; MemoryListener prereg_listener; unsigned iommu_type; + HostIOMMUContext host_icx; Error *error; bool initialized; unsigned long pgsizes; From patchwork Sun Mar 22 12:36:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451765 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1D2E86CA for ; Sun, 22 Mar 2020 12:39:26 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id E9978206F8 for ; Sun, 22 Mar 2020 12:39:25 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E9978206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46040 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzsy-0006qK-QC for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:39:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47929) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzko-0000yq-Oy for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkm-0003uI-QV for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:58 -0400 Received: from mga11.intel.com ([192.55.52.93]:51492) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkm-0003ry-HO for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:56 -0400 IronPort-SDR: yy7Vvlx/ijGKn8pfeoaTjtnI3dIu6MRbKiBIfZ1WV7OENlhXWfCQZ8Np753KsuGq8ux3eazZ72 KaXEHxHUejww== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: V/nzAlH9YqHMTcQkZyxThK6ne48aqyQs4WOfCN84p6KT3j4E3B4rCPLfCfapymZhPVUusNrfsx 8gAn6nhB0UOQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664377" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 09/22] vfio/common: check PASID alloc/free availability Date: Sun, 22 Mar 2020 05:36:06 -0700 Message-Id: <1584880579-12178-10-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 192.55.52.93 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" VFIO exposes host IOMMU dual-stage DMA translation programming capability to userspace by VFIO_TYPE1_NESTING_IOMMU type. However, userspace needs more info on the nesting type. e.g. the supported stage 1 format and PASID alloc/free request availability. This patch gets the iommu nesting cap info from kernel by using IOCTL VFIO_IOMMU_GET_INFO. And checks the HOST_IOMMU_PASID_REQUEST bit in the nesting capabilities. This patch referred some code from Shameer Kolothum. https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg03759.html Cc: Kevin Tian Cc: Jacob Pan Cc: Peter Xu Cc: Eric Auger Cc: Yi Sun Cc: David Gibson Cc: Alex Williamson Signed-off-by: Shameer Kolothum Signed-off-by: Liu Yi L --- hw/vfio/common.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index e4f5f10..e0f2828 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1223,6 +1223,84 @@ static int vfio_host_icx_pasid_free(HostIOMMUContext *host_icx, 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) +{ + + size_t argsz = sizeof(struct vfio_iommu_type1_info); + + *info = g_malloc0(argsz); + +retry: + (*info)->argsz = argsz; + + if (ioctl(container->fd, VFIO_IOMMU_GET_INFO, *info)) { + g_free(*info); + *info = NULL; + return -errno; + } + + if (((*info)->argsz > argsz)) { + argsz = (*info)->argsz; + *info = g_realloc(*info, argsz); + goto retry; + } + + return 0; +} + +static struct vfio_info_cap_header * +vfio_get_iommu_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) +{ + struct vfio_info_cap_header *hdr; + void *ptr = info; + + if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) { + return NULL; + } + + for (hdr = ptr + info->cap_offset; hdr != ptr; hdr = ptr + hdr->next) { + if (hdr->id == id) { + return hdr; + } + } + + 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; + int ret; + + 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 -errno; + } + + cap = container_of(hdr, + struct vfio_iommu_type1_info_cap_nesting, header); + *cap_nesting = *cap; + + g_free(info); + return 0; +} + static int vfio_init_container(VFIOContainer *container, int group_fd, Error **errp) { @@ -1256,11 +1334,19 @@ static int vfio_init_container(VFIOContainer *container, int group_fd, } if (iommu_type == VFIO_TYPE1_NESTING_IOMMU) { - /* - * TODO: config flags per host IOMMU nesting capability - * e.g. check if VFIO_TYPE1_NESTING_IOMMU supports PASID - * alloc/free - */ + struct vfio_iommu_type1_info_cap_nesting nesting = { + .nesting_capabilities = 0x0, + .stage1_formats = 0, }; + + ret = vfio_get_nesting_iommu_cap(container, &nesting); + if (ret) { + error_setg_errno(errp, -ret, + "Failed to get nesting iommu cap"); + return ret; + } + + flags |= (nesting.nesting_capabilities & VFIO_IOMMU_PASID_REQS) ? + HOST_IOMMU_PASID_REQUEST : 0; host_iommu_ctx_init(&container->host_icx, sizeof(container->host_icx), TYPE_VFIO_HOST_IOMMU_CONTEXT, From patchwork Sun Mar 22 12:36:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451753 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 86A1F174A for ; Sun, 22 Mar 2020 12:35:50 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 55AD4206F8 for ; Sun, 22 Mar 2020 12:35:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 55AD4206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45988 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzpV-00014p-Dj for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:35:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47947) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkp-0000zQ-K8 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkm-0003uZ-Uz for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:59 -0400 Received: from mga02.intel.com ([134.134.136.20]:41735) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkm-0003ol-M7 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:56 -0400 IronPort-SDR: yzVHgr71Kg+o4t62Sik23YsZ06E2YGamL7tvLV4VmBd+T1+DrWD7wuCYsys0NPGxEI2E+TU/Fu VSGnAJ1Wweqg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: /UWCFhhjSzkWUmhH16kN9TNz6wt1CA5Xw9SVpRut/yrNyw15hDWS28ojNb7ztEDnj1UjcspGz+ l1rS7MKbeoGg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664380" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 10/22] intel_iommu: add virtual command capability support Date: Sun, 22 Mar 2020 05:36:07 -0700 Message-Id: <1584880579-12178-11-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 --- hw/i386/intel_iommu.c | 154 ++++++++++++++++++++++++++++++++++++++++- hw/i386/intel_iommu_internal.h | 37 ++++++++++ hw/i386/trace-events | 1 + include/hw/i386/intel_iommu.h | 10 ++- 4 files changed, 200 insertions(+), 2 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 8d9204f..0c402e4 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2651,6 +2651,129 @@ static void vtd_handle_iectl_write(IntelIOMMUState *s) } } +static int vtd_request_pasid_alloc(IntelIOMMUState *s, uint32_t *pasid) +{ + VTDHostIOMMUContext *vtd_dev_icx; + int ret = -1; + + vtd_iommu_lock(s); + QLIST_FOREACH(vtd_dev_icx, &s->vtd_dev_icx_list, next) { + HostIOMMUContext *host_icx = vtd_dev_icx->host_icx; + + /* + * We'll return the first valid result we got. It's + * a bit hackish in that we don't have a good global + * interface yet to talk to modules like vfio to deliver + * this allocation request, so we're leveraging this + * per-device iommu context to do the same thing just + * to make sure the allocation happens only once. + */ + ret = host_iommu_ctx_pasid_alloc(host_icx, VTD_MIN_HPASID, + VTD_MAX_HPASID, pasid); + if (!ret) { + break; + } + } + vtd_iommu_unlock(s); + + return ret; +} + +static int vtd_request_pasid_free(IntelIOMMUState *s, uint32_t pasid) +{ + VTDHostIOMMUContext *vtd_dev_icx; + int ret = -1; + + vtd_iommu_lock(s); + QLIST_FOREACH(vtd_dev_icx, &s->vtd_dev_icx_list, next) { + HostIOMMUContext *host_icx = vtd_dev_icx->host_icx; + + /* + * Similar with pasid allocation. We'll free the pasid + * on the first successful free operation. It's a bit + * hackish in that we don't have a good global interface + * yet to talk to modules like vfio to deliver this pasid + * free request, so we're leveraging this per-device iommu + * context to do the same thing just to make sure the free + * happens only once. + */ + ret = host_iommu_ctx_pasid_free(host_icx, pasid); + if (!ret) { + break; + } + } + 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; @@ -2939,6 +3062,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); @@ -3470,6 +3610,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->host_icx = host_icx; + QLIST_INSERT_HEAD(&s->vtd_dev_icx_list, vtd_dev_icx, next); } vtd_iommu_unlock(s); @@ -3489,7 +3630,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_iommu_unlock(s); } @@ -3763,6 +3907,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 @@ -3877,6 +4028,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); 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, diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 862033e..1d997a1 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 */ @@ -312,6 +318,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_MIN_HPASID 1 +#define VTD_MAX_HPASID 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 e48bef2..71536a7 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 9b4fc0a..da0a5f7 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -42,7 +42,7 @@ #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 @@ -118,6 +118,7 @@ struct VTDHostIOMMUContext { uint8_t devfn; HostIOMMUContext *host_icx; IntelIOMMUState *iommu_state; + QLIST_ENTRY(VTDHostIOMMUContext) next; }; struct VTDBus { @@ -269,6 +270,9 @@ struct IntelIOMMUState { /* 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 */ @@ -279,6 +283,10 @@ 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 */ + /* * Protects IOMMU states in general. Currently it protects the * per-IOMMU IOTLB cache, and context entry cache in VTDAddressSpace. From patchwork Sun Mar 22 12:36:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451759 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 52F4D1731 for ; Sun, 22 Mar 2020 12:37:37 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 315F4206F8 for ; Sun, 22 Mar 2020 12:37:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 315F4206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46022 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzrE-0004Cc-CX for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:37:36 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47925) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzko-0000yY-Ji for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkm-0003uS-U5 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:58 -0400 Received: from mga02.intel.com ([134.134.136.20]:41752) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkm-0003r4-Ks for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:56 -0400 IronPort-SDR: efFXscCfCJvEHsgMhr+wC3PZVxw4/W+bYsf+jaxd8J0YPAgs3MjRFQG3nP3lWnJL3Bs5hjoY/U thT435E9MArg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: QvDGsNA9ZBcEOyWTIMzNiSca2tEBFABbX9xUjR5L17yx79+V4Fg8H41Pdd2Css9CMZd+qmBElA blz+ouqeYGKw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664383" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 11/22] intel_iommu: process PASID cache invalidation Date: Sun, 22 Mar 2020 05:36:08 -0700 Message-Id: <1584880579-12178-12-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 --- hw/i386/intel_iommu.c | 66 ++++++++++++++++++++++++++++++++++++++---- hw/i386/intel_iommu_internal.h | 12 ++++++++ hw/i386/trace-events | 3 ++ 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 0c402e4..1daeab2 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2395,6 +2395,63 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) return true; } +static int vtd_pasid_cache_dsi(IntelIOMMUState *s, uint16_t domain_id) +{ + return 0; +} + +static int vtd_pasid_cache_psi(IntelIOMMUState *s, + uint16_t domain_id, uint32_t pasid) +{ + return 0; +} + +static int vtd_pasid_cache_gsi(IntelIOMMUState *s) +{ + return 0; +} + +static bool vtd_process_pasid_desc(IntelIOMMUState *s, + VTDInvDesc *inv_desc) +{ + uint16_t domain_id; + uint32_t pasid; + int ret = 0; + + 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; + } + + 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: + ret = vtd_pasid_cache_dsi(s, domain_id); + break; + + case VTD_INV_DESC_PASIDC_PASID_SI: + ret = vtd_pasid_cache_psi(s, domain_id, pasid); + break; + + case VTD_INV_DESC_PASIDC_GLOBAL: + ret = vtd_pasid_cache_gsi(s); + 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 (ret == 0) ? true : false; +} + static bool vtd_process_inv_iec_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { @@ -2501,12 +2558,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 1d997a1..0ca5f0b 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -444,6 +444,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 71536a7..f7cd4e5 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 Sun Mar 22 12:36:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451767 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B96F66CA for ; Sun, 22 Mar 2020 12:39:33 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 878BD206F8 for ; Sun, 22 Mar 2020 12:39:33 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 878BD206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46042 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzt6-0006xp-Oo for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:39:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47999) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkr-00011K-10 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkn-0003uv-Ad for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:00 -0400 Received: from mga02.intel.com ([134.134.136.20]:41767) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkm-0003tR-NO for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:57 -0400 IronPort-SDR: 2gWyshc1MRW/yr7CTciqhmJvaUi2C+oQsulfnMgOGKfjL/apAN9G0nxNi/SM/uZ2gpsMRHR73K kD63Omk6U0uA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:38 -0700 IronPort-SDR: /woCwEl8emTpg74tTNEoD/COlbSs6KrhJrIJlYzI3KAANa1J+qy2ZtzoPrcIQFK98RGhfElVrk jMw372LTIYnw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664387" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 12/22] intel_iommu: add PASID cache management infrastructure Date: Sun, 22 Mar 2020 05:36:09 -0700 Message-Id: <1584880579-12178-13-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 --- hw/i386/intel_iommu.c | 394 +++++++++++++++++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 14 ++ hw/i386/trace-events | 1 + include/hw/i386/intel_iommu.h | 33 +++- 4 files changed, 441 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 1daeab2..c985cae 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -40,6 +40,7 @@ #include "kvm_i386.h" #include "migration/vmstate.h" #include "trace.h" +#include "qemu/jhash.h" /* context entry operations */ #define VTD_CE_GET_RID2PASID(ce) \ @@ -65,6 +66,8 @@ 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 " @@ -276,6 +279,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); } @@ -686,6 +690,11 @@ 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 bool vtd_pdire_present(VTDPASIDDirEntry *pdire) { return pdire->val & 1; @@ -2395,19 +2404,402 @@ 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 cached the pasid entry in &vtd_pasid_as. Also + * notifies host about the new pasid binding. Caller of this + * function should hold iommu_lock. + */ +static inline void vtd_fill_in_pe_in_cache(IntelIOMMUState *s, + VTDPASIDAddressSpace *vtd_pasid_as, + VTDPASIDEntry *pe) +{ + VTDPASIDCacheEntry *pc_entry = &vtd_pasid_as->pasid_cache_entry; + + pc_entry->pasid_entry = *pe; + pc_entry->pasid_cache_gen = s->pasid_cache_gen; + /* + * TODO: + * - send pasid bind to host for passthru devices + */ +} + +/** + * This function updates the pasid entry cached in &vtd_pasid_as. + * Caller of this function should hold iommu_lock. + */ +static void vtd_update_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; + } + + vtd_fill_in_pe_in_cache(s, vtd_pasid_as, pe); +} + +/** + * This function is used to clear pasid_cache_gen of 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; + + if (!(pc_entry->pasid_cache_gen == s->pasid_cache_gen)) { + return false; + } + + switch (pc_info->flags & VTD_PASID_CACHE_INFO_MASK) { + 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: + break; + default: + error_report("invalid pc_info->flags"); + 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_update_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->context_cache_entry.context_cache_gen = 0; + vtd_pasid_as->pasid = pasid; + vtd_pasid_as->pasid_cache_entry.pasid_cache_gen = 0; + g_hash_table_insert(s->vtd_pasid_as, new_key, vtd_pasid_as); + } + return vtd_pasid_as; +} + static int vtd_pasid_cache_dsi(IntelIOMMUState *s, uint16_t domain_id) { + VTDPASIDCacheInfo pc_info; + + trace_vtd_pasid_cache_dsi(domain_id); + + pc_info.flags = VTD_PASID_CACHE_DOMSI; + pc_info.domain_id = domain_id; + + /* + * Loop all existing pasid caches and update them. + */ + vtd_iommu_lock(s); + g_hash_table_foreach_remove(s->vtd_pasid_as, + vtd_flush_pasid, &pc_info); + vtd_iommu_unlock(s); + + /* + * TODO: + * Domain selective PASID cache invalidation flushes + * all the pasid caches within a domain. To be safe, + * after invalidating the pasid caches, emulator needs + * to replay the pasid bindings by walking guest pasid + * dir and pasid table. e.g. When the guest setup a new + * PASID entry then send a PASID DSI. + */ return 0; } static int vtd_pasid_cache_psi(IntelIOMMUState *s, uint16_t domain_id, uint32_t pasid) { + VTDPASIDCacheInfo pc_info; + VTDHostIOMMUContext *vtd_dev_icx; + + /* PASID selective implies a DID selective */ + pc_info.flags = VTD_PASID_CACHE_PASIDSI; + pc_info.domain_id = domain_id; + pc_info.pasid = pasid; + + /* + * Regards to a pasid selective pasid cache invalidation (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 + * + * Here the handling of a PSI follows below steps: + * 1) loop all the exisitng 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. + */ + + 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. + */ + QLIST_FOREACH(vtd_dev_icx, &s->vtd_dev_icx_list, next) { + VTDPASIDAddressSpace *vtd_pasid_as; + VTDPASIDCacheEntry *pc_entry; + VTDPASIDEntry pe; + VTDBus *vtd_bus = vtd_dev_icx->vtd_bus; + uint16_t devfn = vtd_dev_icx->devfn; + int bus_n = pci_bus_num(vtd_bus->bus); + + /* i) fetch vtd_pasid_as and check if it is valid */ + vtd_pasid_as = vtd_add_find_pasid_as(s, vtd_bus, + devfn, pasid); + pc_entry = &vtd_pasid_as->pasid_cache_entry; + if (s->pasid_cache_gen == pc_entry->pasid_cache_gen) { + /* + * pasid_cache_gen equals to s->pasid_cache_gen means + * vtd_pasid_as is valid after the above s->vtd_pasid_as + * updates in Step 1. Thus no need for the below steps. + */ + continue; + } + + /* + * ii) vtd_pasid_as is not valid, it's potentailly a new + * pasid bind. Fetch guest pasid entry. + */ + if (vtd_dev_get_pe_from_pasid(s, bus_n, devfn, pasid, &pe)) { + continue; + } + + /* + * iii) pasid entry exists, update pasid cache + * + * Here need to check domain ID since guest pasid entry + * exists. What needs to do are: + * - update the pc_entry in the vtd_pasid_as + * - set proper pc_entry.pasid_cache_gen + * - pass down the latest guest pasid entry config to host + * (will be added in later patch) + */ + if (domain_id == vtd_pe_get_domain_id(&pe)) { + vtd_fill_in_pe_in_cache(s, vtd_pasid_as, &pe); + } + } + + vtd_iommu_unlock(s); return 0; } +/** + * 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.flags = VTD_PASID_CACHE_GLOBAL; + + /* + * Reset pasid cache is a big hammer, so use + * g_hash_table_foreach_remove which will free + * the vtd_pasid_as instances, indicates the + * cached pasid_cache_gen would be set to 0. + */ + g_hash_table_foreach_remove(s->vtd_pasid_as, + vtd_flush_pasid, &pc_info); + s->pasid_cache_gen = 1; +} + static int vtd_pasid_cache_gsi(IntelIOMMUState *s) { + trace_vtd_pasid_cache_gsi(); + + vtd_iommu_lock(s); + s->pasid_cache_gen++; + if (s->pasid_cache_gen > PASID_CACHE_GEN_MAX) { + vtd_pasid_cache_reset(s); + } + vtd_iommu_unlock(s); + + /* + * TODO: + * Global PASID cache invalidation flushes all + * the pasid caches. To be safe, after invalidating + * the pasid caches, emulator needs to replay the + * pasid bindings by walking guest pasid dir and + * pasid table. + */ return 0; } @@ -4110,6 +4502,8 @@ 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 0ca5f0b..01fd95c 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -307,6 +307,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. @@ -515,6 +516,19 @@ 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 +struct VTDPASIDCacheInfo { +#define VTD_PASID_CACHE_GLOBAL (1ULL << 0) +#define VTD_PASID_CACHE_DOMSI (1ULL << 1) +#define VTD_PASID_CACHE_PASIDSI (1ULL << 2) + uint32_t flags; + uint16_t domain_id; + uint32_t pasid; +}; +#define VTD_PASID_CACHE_INFO_MASK (VTD_PASID_CACHE_GLOBAL | \ + VTD_PASID_CACHE_DOMSI | \ + VTD_PASID_CACHE_PASIDSI) +typedef struct VTDPASIDCacheInfo VTDPASIDCacheInfo; + /* PASID Table Related Definitions */ #define VTD_PASID_DIR_BASE_ADDR_MASK (~0xfffULL) #define VTD_PASID_TABLE_BASE_ADDR_MASK (~0xfffULL) diff --git a/hw/i386/trace-events b/hw/i386/trace-events index f7cd4e5..60d20c1 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 da0a5f7..9782ac4 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -65,6 +65,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 { @@ -97,6 +99,31 @@ struct VTDPASIDEntry { uint64_t val[8]; }; +struct pasid_key { + uint32_t pasid; + uint16_t sid; +}; + +struct VTDPASIDCacheEntry { + /* + * The cache entry is obsolete if + * pasid_cache_gen!=IntelIOMMUState.pasid_cache_gen + */ + uint32_t pasid_cache_gen; + 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; @@ -267,6 +294,9 @@ 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 */ +#define PASID_CACHE_GEN_MAX 512 + uint32_t pasid_cache_gen; /* Should be in [1,MAX] */ /* list of registered notifiers */ QLIST_HEAD(, VTDAddressSpace) vtd_as_with_notifiers; @@ -289,7 +319,8 @@ struct IntelIOMMUState { /* * Protects IOMMU states in general. Currently it protects the - * per-IOMMU IOTLB cache, and context entry cache in VTDAddressSpace. + * per-IOMMU IOTLB cache, and context entry cache in VTDAddressSpace, + * and pasid cache in VTDPASIDAddressSpace. * Protect the update/usage of HostIOMMUContext pointer cached in * VTDBus->dev_icx array as array elements may be updated by hotplug */ From patchwork Sun Mar 22 12:36:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451739 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EDC2E6CA for ; Sun, 22 Mar 2020 12:31:58 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id CD2BD20724 for ; Sun, 22 Mar 2020 12:31:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CD2BD20724 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45926 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzll-0002wS-Tc for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:31:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47996) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkq-00011I-Va for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkn-0003vD-Ul for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:00 -0400 Received: from mga02.intel.com ([134.134.136.20]:41752) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkn-0003r4-BN for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:57 -0400 IronPort-SDR: t6KXQOf8gVH6NUcHNwEL6o/BYlzLfme46fKm+igXbU7+SEDplL8x1speFJeb5VFfIzaggTqmEv Xt7QAnJH02fQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: 2PjxvB4qtNOtUpwgE/DzNfuQOYtldOE3+9hEtfhHfVcaaEJNFb2cCjVnkrJMZFR5Lng2yyZit6 t3VJbOn9yPuQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664389" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 13/22] vfio: add bind stage-1 page table support Date: Sun, 22 Mar 2020 05:36:10 -0700 Message-Id: <1584880579-12178-14-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This patch adds bind_stage1_pgtbl() definition in HostIOMMUContextClass, also adds corresponding implementation in VFIO. This is to expose a way 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/iommu/host_iommu_context.c | 49 ++++++++++++++++++++++++++++++- hw/vfio/common.c | 55 ++++++++++++++++++++++++++++++++++- include/hw/iommu/host_iommu_context.h | 26 ++++++++++++++++- 3 files changed, 127 insertions(+), 3 deletions(-) diff --git a/hw/iommu/host_iommu_context.c b/hw/iommu/host_iommu_context.c index af61899..8a53376 100644 --- a/hw/iommu/host_iommu_context.c +++ b/hw/iommu/host_iommu_context.c @@ -69,21 +69,67 @@ int host_iommu_ctx_pasid_free(HostIOMMUContext *host_icx, uint32_t pasid) return hicxc->pasid_free(host_icx, pasid); } +int host_iommu_ctx_bind_stage1_pgtbl(HostIOMMUContext *host_icx, + DualIOMMUStage1BindData *data) +{ + HostIOMMUContextClass *hicxc; + + if (!host_icx) { + return -EINVAL; + } + + hicxc = HOST_IOMMU_CONTEXT_GET_CLASS(host_icx); + if (!hicxc) { + return -EINVAL; + } + + if (!(host_icx->flags & HOST_IOMMU_NESTING) || + !hicxc->bind_stage1_pgtbl) { + return -EINVAL; + } + + return hicxc->bind_stage1_pgtbl(host_icx, data); +} + +int host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *host_icx, + DualIOMMUStage1BindData *data) +{ + HostIOMMUContextClass *hicxc; + + if (!host_icx) { + return -EINVAL; + } + + hicxc = HOST_IOMMU_CONTEXT_GET_CLASS(host_icx); + if (!hicxc) { + return -EINVAL; + } + + if (!(host_icx->flags & HOST_IOMMU_NESTING) || + !hicxc->unbind_stage1_pgtbl) { + return -EINVAL; + } + + return hicxc->unbind_stage1_pgtbl(host_icx, data); +} + void host_iommu_ctx_init(void *_host_icx, size_t instance_size, const char *mrtypename, - uint64_t flags) + uint64_t flags, uint32_t formats) { HostIOMMUContext *host_icx; object_initialize(_host_icx, instance_size, mrtypename); host_icx = HOST_IOMMU_CONTEXT(_host_icx); host_icx->flags = flags; + host_icx->stage1_formats = formats; host_icx->initialized = true; } void host_iommu_ctx_destroy(HostIOMMUContext *host_icx) { host_icx->flags = 0x0; + host_icx->stage1_formats = 0x0; host_icx->initialized = false; } @@ -92,6 +138,7 @@ static void host_icx_init_fn(Object *obj) HostIOMMUContext *host_icx = HOST_IOMMU_CONTEXT(obj); host_icx->flags = 0x0; + host_icx->stage1_formats = 0x0; host_icx->initialized = false; } diff --git a/hw/vfio/common.c b/hw/vfio/common.c index e0f2828..770a785 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1223,6 +1223,52 @@ static int vfio_host_icx_pasid_free(HostIOMMUContext *host_icx, return 0; } +static int vfio_host_icx_bind_stage1_pgtbl(HostIOMMUContext *host_icx, + DualIOMMUStage1BindData *bind_data) +{ + VFIOContainer *container = container_of(host_icx, VFIOContainer, host_icx); + struct vfio_iommu_type1_bind *bind; + unsigned long argsz; + int ret = 0; + + argsz = sizeof(*bind) + sizeof(bind_data->bind_data); + bind = g_malloc0(argsz); + bind->argsz = argsz; + bind->flags = VFIO_IOMMU_BIND_GUEST_PGTBL; + memcpy(&bind->data, &bind_data->bind_data, sizeof(bind_data->bind_data)); + + if (ioctl(container->fd, VFIO_IOMMU_BIND, bind)) { + ret = -errno; + error_report("%s: pasid (%u) bind failed: %d", + __func__, bind_data->pasid, ret); + } + g_free(bind); + return ret; +} + +static int vfio_host_icx_unbind_stage1_pgtbl(HostIOMMUContext *host_icx, + DualIOMMUStage1BindData *bind_data) +{ + VFIOContainer *container = container_of(host_icx, VFIOContainer, host_icx); + struct vfio_iommu_type1_bind *bind; + unsigned long argsz; + int ret = 0; + + argsz = sizeof(*bind) + sizeof(bind_data->bind_data); + bind = g_malloc0(argsz); + bind->argsz = argsz; + bind->flags = VFIO_IOMMU_UNBIND_GUEST_PGTBL; + memcpy(&bind->data, &bind_data->bind_data, sizeof(bind_data->bind_data)); + + if (ioctl(container->fd, VFIO_IOMMU_BIND, bind)) { + ret = -errno; + error_report("%s: pasid (%u) unbind failed: %d", + __func__, bind_data->pasid, ret); + } + g_free(bind); + return ret; +} + /** * Get iommu info from host. Caller of this funcion should free * the memory pointed by the returned pointer stored in @info @@ -1337,6 +1383,7 @@ static int vfio_init_container(VFIOContainer *container, int group_fd, struct vfio_iommu_type1_info_cap_nesting nesting = { .nesting_capabilities = 0x0, .stage1_formats = 0, }; + uint32_t stage1_formats; ret = vfio_get_nesting_iommu_cap(container, &nesting); if (ret) { @@ -1347,10 +1394,14 @@ static int vfio_init_container(VFIOContainer *container, int group_fd, flags |= (nesting.nesting_capabilities & VFIO_IOMMU_PASID_REQS) ? HOST_IOMMU_PASID_REQUEST : 0; + flags |= HOST_IOMMU_NESTING; + stage1_formats = nesting.stage1_formats; + host_iommu_ctx_init(&container->host_icx, sizeof(container->host_icx), TYPE_VFIO_HOST_IOMMU_CONTEXT, - flags); + flags, + stage1_formats); } container->iommu_type = iommu_type; @@ -1943,6 +1994,8 @@ static void vfio_host_iommu_context_class_init(ObjectClass *klass, hicxc->pasid_alloc = vfio_host_icx_pasid_alloc; hicxc->pasid_free = vfio_host_icx_pasid_free; + hicxc->bind_stage1_pgtbl = vfio_host_icx_bind_stage1_pgtbl; + hicxc->unbind_stage1_pgtbl = vfio_host_icx_unbind_stage1_pgtbl; } 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 5f11a4c..97c9473 100644 --- a/include/hw/iommu/host_iommu_context.h +++ b/include/hw/iommu/host_iommu_context.h @@ -41,6 +41,7 @@ TYPE_HOST_IOMMU_CONTEXT) typedef struct HostIOMMUContext HostIOMMUContext; +typedef struct DualIOMMUStage1BindData DualIOMMUStage1BindData; typedef struct HostIOMMUContextClass { /* private */ @@ -54,6 +55,16 @@ typedef struct HostIOMMUContextClass { /* Reclaim pasid from HostIOMMUContext (a.k.a. host software) */ int (*pasid_free)(HostIOMMUContext *host_icx, uint32_t pasid); + /* + * Bind stage-1 page table to a hostIOMMU w/ dual stage + * DMA translation capability. + * @bind_data specifies the bind configurations. + */ + int (*bind_stage1_pgtbl)(HostIOMMUContext *dsi_obj, + DualIOMMUStage1BindData *bind_data); + /* Undo a previous bind. @bind_data specifies the unbind info. */ + int (*unbind_stage1_pgtbl)(HostIOMMUContext *dsi_obj, + DualIOMMUStage1BindData *bind_data); } HostIOMMUContextClass; /* @@ -62,17 +73,30 @@ typedef struct HostIOMMUContextClass { struct HostIOMMUContext { Object parent_obj; #define HOST_IOMMU_PASID_REQUEST (1ULL << 0) +#define HOST_IOMMU_NESTING (1ULL << 1) uint64_t flags; + uint32_t stage1_formats; bool initialized; }; +struct DualIOMMUStage1BindData { + uint32_t pasid; + union { + struct iommu_gpasid_bind_data gpasid_bind; + } bind_data; +}; + int host_iommu_ctx_pasid_alloc(HostIOMMUContext *host_icx, uint32_t min, uint32_t max, uint32_t *pasid); int host_iommu_ctx_pasid_free(HostIOMMUContext *host_icx, uint32_t pasid); +int host_iommu_ctx_bind_stage1_pgtbl(HostIOMMUContext *host_icx, + DualIOMMUStage1BindData *data); +int host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *host_icx, + DualIOMMUStage1BindData *data); void host_iommu_ctx_init(void *_host_icx, size_t instance_size, const char *mrtypename, - uint64_t flags); + uint64_t flags, uint32_t formats); void host_iommu_ctx_destroy(HostIOMMUContext *host_icx); #endif From patchwork Sun Mar 22 12:36:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451771 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 266246CA for ; Sun, 22 Mar 2020 12:41:31 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id EE046206F8 for ; Sun, 22 Mar 2020 12:41:30 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EE046206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46084 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzv0-0001Ch-0O for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:41:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47984) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkq-00011B-Jk for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzko-0003vM-13 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:00 -0400 Received: from mga02.intel.com ([134.134.136.20]:41735) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkn-0003ol-I6 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:57 -0400 IronPort-SDR: nfNJActKZEvOkxpMu1D0h8YwK9hUfSjBQ2byPDT6I9u+tF+4dvM9CZbZw2W8awQYBwbask2Qwp nlkrjwyWHbvw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: ynszA//vr04ujZBixMlQ8rbWpYmqA1Br100n2VWTY4/tkVwrgkkRyi82oNzIfWKHHG8qOPfj0i S8kKGcBFMiNQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664392" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 14/22] intel_iommu: bind/unbind guest page table to host Date: Sun, 22 Mar 2020 05:36:11 -0700 Message-Id: <1584880579-12178-15-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 --- hw/i386/intel_iommu.c | 98 +++++++++++++++++++++++++++++++++++++++--- hw/i386/intel_iommu_internal.h | 25 +++++++++++ 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index c985cae..0423c83 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -41,6 +41,7 @@ #include "migration/vmstate.h" #include "trace.h" #include "qemu/jhash.h" +#include /* context entry operations */ #define VTD_CE_GET_RID2PASID(ce) \ @@ -695,6 +696,16 @@ 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_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 bool vtd_pdire_present(VTDPASIDDirEntry *pdire) { return pdire->val & 1; @@ -1856,6 +1867,81 @@ 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 *host_icx; + DualIOMMUStage1BindData *bind_data; + struct iommu_gpasid_bind_data *g_bind_data; + int ret = -1; + + vtd_dev_icx = vtd_bus->dev_icx[devfn]; + if (!vtd_dev_icx) { + return -EINVAL; + } + + host_icx = vtd_dev_icx->host_icx; + if (!host_icx) { + return -EINVAL; + } + + if (!(host_icx->stage1_formats + & IOMMU_PASID_FORMAT_INTEL_VTD)) { + error_report_once("IOMMU Stage 1 format is not compatible!\n"); + } + + bind_data = g_malloc0(sizeof(*bind_data)); + bind_data->pasid = pasid; + g_bind_data = &bind_data->bind_data.gpasid_bind; + + g_bind_data->flags = 0; + g_bind_data->vtd.flags = 0; + switch (op) { + case VTD_PASID_BIND: + case VTD_PASID_UPDATE: + g_bind_data->version = IOMMU_UAPI_VERSION; + 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->vtd.flags = + (VTD_SM_PASID_ENTRY_SRE_BIT(pe->val[2]) ? 1 : 0) + | (VTD_SM_PASID_ENTRY_EAFE_BIT(pe->val[2]) ? 1 : 0) + | (VTD_SM_PASID_ENTRY_PCD_BIT(pe->val[1]) ? 1 : 0) + | (VTD_SM_PASID_ENTRY_PWT_BIT(pe->val[1]) ? 1 : 0) + | (VTD_SM_PASID_ENTRY_EMTE_BIT(pe->val[1]) ? 1 : 0) + | (VTD_SM_PASID_ENTRY_CD_BIT(pe->val[1]) ? 1 : 0); + g_bind_data->vtd.pat = VTD_SM_PASID_ENTRY_PAT(pe->val[1]); + g_bind_data->vtd.emt = VTD_SM_PASID_ENTRY_EMT(pe->val[1]); + ret = host_iommu_ctx_bind_stage1_pgtbl(host_icx, bind_data); + break; + case VTD_PASID_UNBIND: + g_bind_data->version = IOMMU_UAPI_VERSION; + g_bind_data->format = IOMMU_PASID_FORMAT_INTEL_VTD; + g_bind_data->gpgd = 0; + g_bind_data->addr_width = 0; + g_bind_data->hpasid = pasid; + g_bind_data->gpasid = pasid; + g_bind_data->flags |= IOMMU_SVA_GPASID_VAL; + ret = host_iommu_ctx_unbind_stage1_pgtbl(host_icx, bind_data); + break; + default: + error_report_once("Unknown VTDPASIDOp!!!\n"); + break; + } + + g_free(bind_data); + + return ret; +} + /* Do a context-cache device-selective invalidation. * @func_mask: FM field after shifting */ @@ -2481,10 +2567,10 @@ static inline void vtd_fill_in_pe_in_cache(IntelIOMMUState *s, pc_entry->pasid_entry = *pe; pc_entry->pasid_cache_gen = s->pasid_cache_gen; - /* - * TODO: - * - send pasid bind to host for passthru devices - */ + vtd_bind_guest_pasid(s, vtd_pasid_as->vtd_bus, + vtd_pasid_as->devfn, + vtd_pasid_as->pasid, + pe, VTD_PASID_BIND); } /** @@ -2574,11 +2660,13 @@ static gboolean vtd_flush_pasid(gpointer key, gpointer value, * - when pasid-base-iotlb(piotlb) infrastructure is ready, * should invalidate QEMU piotlb togehter with this change. */ + return false; remove: + vtd_bind_guest_pasid(s, vtd_bus, devfn, + pasid, NULL, VTD_PASID_UNBIND); /* * 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. */ diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 01fd95c..4451acf 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -516,6 +516,20 @@ 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 VTD_DUAL_STAGE_UAPI { + UAPI_BIND_GPASID, + UAPI_NUM +}; +typedef enum VTD_DUAL_STAGE_UAPI VTD_DUAL_STAGE_UAPI; + +enum VTDPASIDOp { + VTD_PASID_BIND, + VTD_PASID_UNBIND, + VTD_PASID_UPDATE, + VTD_OP_NUM +}; +typedef enum VTDPASIDOp VTDPASIDOp; + struct VTDPASIDCacheInfo { #define VTD_PASID_CACHE_GLOBAL (1ULL << 0) #define VTD_PASID_CACHE_DOMSI (1ULL << 1) @@ -552,6 +566,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 Sun Mar 22 12:36:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451769 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DB6AC6CA for ; Sun, 22 Mar 2020 12:39:37 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id B10A4206F8 for ; Sun, 22 Mar 2020 12:39:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B10A4206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46044 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFztA-000742-SA for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:39:36 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47987) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkq-00011C-KF for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzko-0003vU-36 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:00 -0400 Received: from mga02.intel.com ([134.134.136.20]:41767) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkn-0003tR-OE for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:57 -0400 IronPort-SDR: +dtA/N6rJZW5aEe54BWYR8aW005OPIvTdwK0qLgLKOOsgpCOrYzsaEjfVZGgi/ymVy2Ntwss31 Kq2J7itY/hjw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: 1DrJEvFmLOUcp5Ps0uHn86gzLlpL+bJdRsJ26xeTLP+MrzZiB38bQjF8QXbJV1pZGNppzr8EHh JgP381s0YN2A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664395" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 15/22] intel_iommu: replay guest pasid bindings to host Date: Sun, 22 Mar 2020 05:36:12 -0700 Message-Id: <1584880579-12178-16-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" This patch adds guest pasid bindings replay for domain selective pasid cache invalidation(dsi) and global pasid cache invalidation by walking guest pasid table. Reason: Guest OS may flush the pasid cache with a larger granularity. e.g. guest does a svm_bind() but flush the pasid cache with global or domain selective pasid cache invalidation instead of pasid selective(psi) pasid cache invalidation. Regards to such case, it works in host. Per spec, a global or domain selective pasid cache invalidation should be able to cover what a pasid selective invalidation does. The only concern is performance deduction since dsi and global cache invalidation will flush more than psi. To align with native, vIOMMU needs emulator needs to do replay for the two invalidation granularity to reflect the latest pasid bindings in guest pasid table. 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 | 128 ++++++++++++++++++++++++++++++++++++++++- hw/i386/intel_iommu_internal.h | 1 + 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 0423c83..8ec638f 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2717,6 +2717,130 @@ static VTDPASIDAddressSpace *vtd_add_find_pasid_as(IntelIOMMUState *s, return vtd_pasid_as; } +/** + * Constant information used during pasid table walk + @vtd_bus, @devfn: device info + * @flags: indicates if it is domain selective walk + * @did: domain ID of the pasid table walk + */ +typedef struct { + VTDBus *vtd_bus; + uint16_t devfn; +#define VTD_PASID_TABLE_DID_SEL_WALK (1ULL << 0); + uint32_t flags; + uint16_t did; +} vtd_pasid_table_walk_info; + +/** + * Caller of this function should hold iommu_lock. + */ +static bool vtd_sm_pasid_table_walk_one(IntelIOMMUState *s, + dma_addr_t pt_base, + int start, + int end, + vtd_pasid_table_walk_info *info) +{ + VTDPASIDEntry pe; + int pasid = start; + int pasid_next; + VTDPASIDAddressSpace *vtd_pasid_as; + VTDPASIDCacheEntry *pc_entry; + + 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); + pc_entry = &vtd_pasid_as->pasid_cache_entry; + if (s->pasid_cache_gen == pc_entry->pasid_cache_gen) { + vtd_update_pe_in_cache(s, vtd_pasid_as, &pe); + } else { + vtd_fill_in_pe_in_cache(s, vtd_pasid_as, &pe); + } + } + pasid = pasid_next; + } + return true; +} + +/* + * 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, + vtd_pasid_table_walk_info *info) +{ + VTDPASIDDirEntry pdire; + int pasid = start; + int pasid_next; + dma_addr_t pt_base; + + while (pasid < end) { + pasid_next = pasid + VTD_PASID_TBL_ENTRY_NUM; + 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; + if (!vtd_sm_pasid_table_walk_one(s, + pt_base, pasid, pasid_next, info)) { + break; + } + } + pasid = pasid_next; + } +} + +/** + * This function replay the guest pasid bindings to hots by + * walking the guest PASID table. This ensures host will have + * latest guest pasid bindings. + */ +static void vtd_replay_guest_pasid_bindings(IntelIOMMUState *s, + uint16_t *did, + bool is_dsi) +{ + VTDContextEntry ce; + VTDHostIOMMUContext *vtd_dev_icx; + int bus_n, devfn; + vtd_pasid_table_walk_info info; + + if (is_dsi) { + info.flags = VTD_PASID_TABLE_DID_SEL_WALK; + info.did = *did; + } + + /* + * 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. + */ + vtd_iommu_lock(s); + QLIST_FOREACH(vtd_dev_icx, &s->vtd_dev_icx_list, next) { + bus_n = pci_bus_num(vtd_dev_icx->vtd_bus->bus); + devfn = vtd_dev_icx->devfn; + + if (!vtd_dev_to_context_entry(s, bus_n, devfn, &ce)) { + info.vtd_bus = vtd_dev_icx->vtd_bus; + info.devfn = devfn; + vtd_sm_pasid_table_walk(s, + VTD_CE_GET_PASID_DIR_TABLE(&ce), + 0, + VTD_MAX_HPASID, + &info); + } + } + vtd_iommu_unlock(s); +} + static int vtd_pasid_cache_dsi(IntelIOMMUState *s, uint16_t domain_id) { VTDPASIDCacheInfo pc_info; @@ -2735,7 +2859,6 @@ static int vtd_pasid_cache_dsi(IntelIOMMUState *s, uint16_t domain_id) vtd_iommu_unlock(s); /* - * TODO: * Domain selective PASID cache invalidation flushes * all the pasid caches within a domain. To be safe, * after invalidating the pasid caches, emulator needs @@ -2743,6 +2866,7 @@ static int vtd_pasid_cache_dsi(IntelIOMMUState *s, uint16_t domain_id) * dir and pasid table. e.g. When the guest setup a new * PASID entry then send a PASID DSI. */ + vtd_replay_guest_pasid_bindings(s, &domain_id, true); return 0; } @@ -2881,13 +3005,13 @@ static int vtd_pasid_cache_gsi(IntelIOMMUState *s) vtd_iommu_unlock(s); /* - * TODO: * Global PASID cache invalidation flushes all * the pasid caches. To be safe, after invalidating * the pasid caches, emulator needs to replay the * pasid bindings by walking guest pasid dir and * pasid table. */ + vtd_replay_guest_pasid_bindings(s, NULL, false); return 0; } diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 4451acf..b0a324c 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -554,6 +554,7 @@ typedef struct VTDPASIDCacheInfo VTDPASIDCacheInfo; #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 From patchwork Sun Mar 22 12:36:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451761 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E1F74174A for ; Sun, 22 Mar 2020 12:37:37 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id C19BD206F8 for ; Sun, 22 Mar 2020 12:37:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C19BD206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46025 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzrE-0004FF-Va for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:37:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47983) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzkq-000116-IU for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzko-0003wA-NY for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:00 -0400 Received: from mga02.intel.com ([134.134.136.20]:41752) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzko-0003r4-BF for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:58 -0400 IronPort-SDR: EAD78Z2q5XVfkASCv30MZRcU5zvIYBO0EZ5RZXngzuqzuNZ5agQ6KHdXmaq6RP+XkcYVEvu7t7 3wukI26q50nQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: m0FMa1j14SLMTJDfMPvZGGowYjbYFtV2yHXCY1vHFYcRBLR83S7gdbmv3ZFfO1VA4fCdSlWt/l 5qqIgF7lxBYQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664399" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 16/22] intel_iommu: replay pasid binds after context cache invalidation Date: Sun, 22 Mar 2020 05:36:13 -0700 Message-Id: <1584880579-12178-17-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 | 68 ++++++++++++++++++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 6 +++- hw/i386/trace-events | 1 + 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 8ec638f..1e0ccde 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -68,6 +68,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_replay_guest_pasid_bindings(IntelIOMMUState *s, + uint16_t *did, bool is_dsi); +static void vtd_pasid_cache_devsi(IntelIOMMUState *s, + VTDBus *vtd_bus, uint16_t devfn); static void vtd_panic_require_caching_mode(void) { @@ -1865,6 +1869,8 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s) * VT-d emulation codes. */ vtd_iommu_replay_all(s); + + vtd_replay_guest_pasid_bindings(s, NULL, false); } /** @@ -1999,6 +2005,22 @@ 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) + * modify the pasid cache gen and pasid-based iotlb gen + * value (will be added in following patches) + * 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); } } } @@ -2631,6 +2653,12 @@ static gboolean vtd_flush_pasid(gpointer key, gpointer value, /* Fall through */ case VTD_PASID_CACHE_GLOBAL: 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->flags"); abort(); @@ -2971,6 +2999,46 @@ static int vtd_pasid_cache_psi(IntelIOMMUState *s, return 0; } +static void vtd_pasid_cache_devsi(IntelIOMMUState *s, + VTDBus *vtd_bus, uint16_t devfn) +{ + VTDPASIDCacheInfo pc_info; + VTDContextEntry ce; + VTDHostIOMMUContext *vtd_dev_icx; + vtd_pasid_table_walk_info info; + + trace_vtd_pasid_cache_devsi(devfn); + + pc_info.flags = VTD_PASID_CACHE_DEVSI; + pc_info.vtd_bus = vtd_bus; + pc_info.devfn = devfn; + + vtd_iommu_lock(s); + g_hash_table_foreach_remove(s->vtd_pasid_as, vtd_flush_pasid, &pc_info); + + /* + * To be safe, after invalidating the pasid caches, + * emulator needs to replay the pasid bindings by + * walking guest pasid dir and pasid table. + */ + vtd_dev_icx = vtd_bus->dev_icx[devfn]; + if (vtd_dev_icx && vtd_dev_icx->host_icx && + !vtd_dev_to_context_entry(s, pci_bus_num(vtd_bus->bus), + devfn, &ce)) { + info.flags = 0x0; + info.did = 0; + info.vtd_bus = vtd_bus; + info.devfn = devfn; + vtd_sm_pasid_table_walk(s, + VTD_CE_GET_PASID_DIR_TABLE(&ce), + 0, + VTD_MAX_HPASID, + &info); + } + + vtd_iommu_unlock(s); +} + /** * 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 b0a324c..6f32d7b 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -534,13 +534,17 @@ struct VTDPASIDCacheInfo { #define VTD_PASID_CACHE_GLOBAL (1ULL << 0) #define VTD_PASID_CACHE_DOMSI (1ULL << 1) #define VTD_PASID_CACHE_PASIDSI (1ULL << 2) +#define VTD_PASID_CACHE_DEVSI (1ULL << 3) uint32_t flags; uint16_t domain_id; uint32_t pasid; + VTDBus *vtd_bus; + uint16_t devfn; }; #define VTD_PASID_CACHE_INFO_MASK (VTD_PASID_CACHE_GLOBAL | \ VTD_PASID_CACHE_DOMSI | \ - VTD_PASID_CACHE_PASIDSI) + VTD_PASID_CACHE_PASIDSI | \ + VTD_PASID_CACHE_DEVSI) typedef struct VTDPASIDCacheInfo VTDPASIDCacheInfo; /* PASID Table Related Definitions */ diff --git a/hw/i386/trace-events b/hw/i386/trace-events index 60d20c1..3853fa8 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 Sun Mar 22 12:36:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451763 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 119C96CA for ; Sun, 22 Mar 2020 12:37:42 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id E5493206F8 for ; Sun, 22 Mar 2020 12:37:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E5493206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46026 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzrJ-0004MQ-36 for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:37:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47926) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzko-0000ye-Kp for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkm-0003ue-Vg for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:58 -0400 Received: from mga11.intel.com ([192.55.52.93]:51489) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzkm-0003r7-Ls for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:30:56 -0400 IronPort-SDR: Oept8NJajjsl4dhISVEXn/on0xLw6z8Z6pGf2HC/zWx8HbSeAe5ZiKgBg3tRms3PZIlb7vwZOf ZjMLxHmYuS6w== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: +Ixx8tQ4PuyCq3kxQRsbUgAhz1FaTZuqouu8hIUEtDk0yK2tI91DdTh5z5zdl7vOquVcfh0Urc zBv5rD8sWLcg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664402" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 17/22] intel_iommu: do not pass down pasid bind for PASID #0 Date: Sun, 22 Mar 2020 05:36:14 -0700 Message-Id: <1584880579-12178-18-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 192.55.52.93 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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://lkml.org/lkml/2019/9/23/297 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 Reviewed-by: Peter Xu --- 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 1e0ccde..b007715 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1886,6 +1886,16 @@ static int vtd_bind_guest_pasid(IntelIOMMUState *s, VTDBus *vtd_bus, struct iommu_gpasid_bind_data *g_bind_data; int ret = -1; + if (pasid < VTD_MIN_HPASID) { + /* + * 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) { return -EINVAL; From patchwork Sun Mar 22 12:36:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451777 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F0FFB1731 for ; Sun, 22 Mar 2020 12:42:58 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id CE2E1206F8 for ; Sun, 22 Mar 2020 12:42:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CE2E1206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46110 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzwQ-0003re-1E for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:42:58 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:48068) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzl0-0001FC-5R for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzky-000409-Kw for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:09 -0400 Received: from mga02.intel.com ([134.134.136.20]:41735) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzky-0003ol-CY for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:08 -0400 IronPort-SDR: OQu8jpe5IahkoIDU/Hulc1/SHyzoOX+PgiKSNI31HVYv0lEkvxsyUEzBiz75POIvi3tYl5CyaY gZOqEZ1E8JAg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: 9JFGenLxezvZArebX0ilx4WPN6XHUk9n6XDRyPOdH2VNlKSvn00iKYx84XGJmj6z2kEkrGFTX9 MXsCQX+N7/pA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664405" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 18/22] vfio: add support for flush iommu stage-1 cache Date: Sun, 22 Mar 2020 05:36:15 -0700 Message-Id: <1584880579-12178-19-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 Signed-off-by: Liu Yi L Acked-by: Peter Xu --- hw/iommu/host_iommu_context.c | 19 +++++++++++++++++++ hw/vfio/common.c | 24 ++++++++++++++++++++++++ include/hw/iommu/host_iommu_context.h | 14 ++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/hw/iommu/host_iommu_context.c b/hw/iommu/host_iommu_context.c index 8a53376..4bff1a1 100644 --- a/hw/iommu/host_iommu_context.c +++ b/hw/iommu/host_iommu_context.c @@ -113,6 +113,25 @@ int host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *host_icx, return hicxc->unbind_stage1_pgtbl(host_icx, data); } +int host_iommu_ctx_flush_stage1_cache(HostIOMMUContext *host_icx, + DualIOMMUStage1Cache *cache) +{ + HostIOMMUContextClass *hicxc; + + hicxc = HOST_IOMMU_CONTEXT_GET_CLASS(host_icx); + + if (!hicxc) { + return -EINVAL; + } + + if (!(host_icx->flags & HOST_IOMMU_NESTING) || + !hicxc->flush_stage1_cache) { + return -EINVAL; + } + + return hicxc->flush_stage1_cache(host_icx, cache); +} + void host_iommu_ctx_init(void *_host_icx, size_t instance_size, const char *mrtypename, uint64_t flags, uint32_t formats) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 770a785..e69fe94 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1269,6 +1269,29 @@ static int vfio_host_icx_unbind_stage1_pgtbl(HostIOMMUContext *host_icx, return ret; } +static int vfio_host_icx_flush_stage1_cache(HostIOMMUContext *host_icx, + DualIOMMUStage1Cache *cache) +{ + VFIOContainer *container = container_of(host_icx, VFIOContainer, host_icx); + struct vfio_iommu_type1_cache_invalidate *cache_inv; + unsigned long argsz; + int ret = 0; + + argsz = sizeof(*cache_inv) + sizeof(cache->cache_info); + cache_inv = g_malloc0(argsz); + cache_inv->argsz = argsz; + cache_inv->flags = 0; + memcpy(&cache_inv->cache_info, &cache->cache_info, + sizeof(cache->cache_info)); + + if (ioctl(container->fd, VFIO_IOMMU_CACHE_INVALIDATE, cache_inv)) { + error_report("%s: iommu cache flush failed: %d", __func__, -errno); + ret = -errno; + } + g_free(cache_inv); + return ret; +} + /** * Get iommu info from host. Caller of this funcion should free * the memory pointed by the returned pointer stored in @info @@ -1996,6 +2019,7 @@ static void vfio_host_iommu_context_class_init(ObjectClass *klass, hicxc->pasid_free = vfio_host_icx_pasid_free; hicxc->bind_stage1_pgtbl = vfio_host_icx_bind_stage1_pgtbl; hicxc->unbind_stage1_pgtbl = vfio_host_icx_unbind_stage1_pgtbl; + hicxc->flush_stage1_cache = vfio_host_icx_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 97c9473..6230daa 100644 --- a/include/hw/iommu/host_iommu_context.h +++ b/include/hw/iommu/host_iommu_context.h @@ -42,6 +42,7 @@ typedef struct HostIOMMUContext HostIOMMUContext; typedef struct DualIOMMUStage1BindData DualIOMMUStage1BindData; +typedef struct DualIOMMUStage1Cache DualIOMMUStage1Cache; typedef struct HostIOMMUContextClass { /* private */ @@ -65,6 +66,12 @@ typedef struct HostIOMMUContextClass { /* Undo a previous bind. @bind_data specifies the unbind info. */ int (*unbind_stage1_pgtbl)(HostIOMMUContext *dsi_obj, DualIOMMUStage1BindData *bind_data); + /* + * Propagate stage-1 cache flush to host IOMMU, cache + * info specifid in @cache + */ + int (*flush_stage1_cache)(HostIOMMUContext *host_icx, + DualIOMMUStage1Cache *cache); } HostIOMMUContextClass; /* @@ -86,6 +93,11 @@ struct DualIOMMUStage1BindData { } bind_data; }; +struct DualIOMMUStage1Cache { + uint32_t pasid; + struct iommu_cache_invalidate_info cache_info; +}; + int host_iommu_ctx_pasid_alloc(HostIOMMUContext *host_icx, uint32_t min, uint32_t max, uint32_t *pasid); int host_iommu_ctx_pasid_free(HostIOMMUContext *host_icx, uint32_t pasid); @@ -93,6 +105,8 @@ int host_iommu_ctx_bind_stage1_pgtbl(HostIOMMUContext *host_icx, DualIOMMUStage1BindData *data); int host_iommu_ctx_unbind_stage1_pgtbl(HostIOMMUContext *host_icx, DualIOMMUStage1BindData *data); +int host_iommu_ctx_flush_stage1_cache(HostIOMMUContext *host_icx, + DualIOMMUStage1Cache *cache); void host_iommu_ctx_init(void *_host_icx, size_t instance_size, const char *mrtypename, From patchwork Sun Mar 22 12:36:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451773 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C40C71731 for ; Sun, 22 Mar 2020 12:41:46 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id A35DF206F8 for ; Sun, 22 Mar 2020 12:41:46 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A35DF206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46088 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzvF-0001ja-OZ for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:41:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:48070) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzl0-0001FP-6E for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzky-00040K-QC for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:10 -0400 Received: from mga02.intel.com ([134.134.136.20]:41767) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzky-0003tR-HA for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:08 -0400 IronPort-SDR: amio3fMC2hm2pmeWIOZ5mwre9RcSahs0wKI2jpemKL2qabWTftQ1p4SvqoH+X/KF6YbmSnPrCC HtU1p/u40tIg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: uyISaeauoF3ZdiNEazpdZiHyXFJZKy4My45lYzCdL0OBHulKrK8KPxReqjGlM7TNeqS0v74FGo AkG0VqI4jnIA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664410" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 19/22] intel_iommu: process PASID-based iotlb invalidation Date: Sun, 22 Mar 2020 05:36:16 -0700 Message-Id: <1584880579-12178-20-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 Signed-off-by: Liu Yi L --- hw/i386/intel_iommu.c | 57 ++++++++++++++++++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 13 ++++++++++ 2 files changed, 70 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index b007715..b9ac07d 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3134,6 +3134,59 @@ static bool vtd_process_pasid_desc(IntelIOMMUState *s, return (ret == 0) ? 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]); + if (am > VTD_MAMV) { + error_report_once("Invalid am, > max am value, hi: 0x%" PRIx64 + " lo: 0x%" PRIx64, inv_desc->val[1], inv_desc->val[0]); + return false; + } + 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) { @@ -3248,6 +3301,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 6f32d7b..314e2c4 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -457,6 +457,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 Sun Mar 22 12:36:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451749 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C58A81731 for ; Sun, 22 Mar 2020 12:33:56 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id A45E020724 for ; Sun, 22 Mar 2020 12:33:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A45E020724 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45954 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFznf-0006Ip-QC for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:33:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:48085) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzl0-0001Gg-T9 for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzkz-00040e-6u for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:10 -0400 Received: from mga02.intel.com ([134.134.136.20]:41752) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzky-0003r4-Tg for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:09 -0400 IronPort-SDR: zQSVixKM/IXbDb1s5vrKCZrM+qGhS+CMO1+ya36+ThP2W+JSNrVFfXlzQX+/f4SgMqr2kjbeGG OcZtuJpEWwMQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: SLLOdTgyyrKTFMGw5Yl8cEyLsmxlekfnBvxw38wuSKZHkTg4i9p4l/kLYVHhyUfhNUuAhKR+h5 uROmuERj0Zcw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664414" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 20/22] intel_iommu: propagate PASID-based iotlb invalidation to host Date: Sun, 22 Mar 2020 05:36:17 -0700 Message-Id: <1584880579-12178-21-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 Reviewed-by: Peter Xu --- hw/i386/intel_iommu.c | 139 +++++++++++++++++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 7 +++ 2 files changed, 146 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index b9ac07d..10d314d 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3134,15 +3134,154 @@ static bool vtd_process_pasid_desc(IntelIOMMUState *s, return (ret == 0) ? true : false; } +/** + * Caller of this function should hold iommu_lock. + */ +static void vtd_invalidate_piotlb(IntelIOMMUState *s, + VTDBus *vtd_bus, + int devfn, + DualIOMMUStage1Cache *stage1_cache) +{ + VTDHostIOMMUContext *vtd_dev_icx; + HostIOMMUContext *host_icx; + + vtd_dev_icx = vtd_bus->dev_icx[devfn]; + if (!vtd_dev_icx) { + goto out; + } + host_icx = vtd_dev_icx->host_icx; + if (!host_icx) { + goto out; + } + if (host_iommu_ctx_flush_stage1_cache(host_icx, stage1_cache)) { + error_report("Cache flush failed"); + } +out: + return; +} + +static inline bool vtd_pasid_cache_valid( + VTDPASIDAddressSpace *vtd_pasid_as) +{ + return vtd_pasid_as->iommu_state && + (vtd_pasid_as->iommu_state->pasid_cache_gen + == vtd_pasid_as->pasid_cache_entry.pasid_cache_gen); +} + +/** + * 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; + uint16_t did; + + /* + * Needs to check whether the pasid entry cache stored in + * vtd_pasid_as is valid or not. "invalid" means the pasid + * cache has been flushed, thus host should have done piotlb + * invalidation together with a pasid cache invalidation, so + * no need to pass down piotlb invalidation to host for better + * performance. Only when pasid entry cache is "valid", should + * a piotlb invalidation be propagated to host since it means + * guest just modified a mapping in its page table. + */ + if (!vtd_pasid_cache_valid(vtd_pasid_as)) { + return; + } + + did = vtd_pe_get_domain_id( + &(vtd_pasid_as->pasid_cache_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->stage1_cache); + } + + /* + * 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; + DualIOMMUStage1Cache *stage1_cache; + struct iommu_cache_invalidate_info *cache_info; + + stage1_cache = g_malloc0(sizeof(*stage1_cache)); + stage1_cache->pasid = pasid; + + cache_info = &stage1_cache->cache_info; + cache_info->version = IOMMU_UAPI_VERSION; + cache_info->cache = IOMMU_CACHE_INV_TYPE_IOTLB; + cache_info->granularity = IOMMU_INV_GRANU_PASID; + cache_info->pasid_info.pasid = pasid; + cache_info->pasid_info.flags = IOMMU_INV_PASID_FLAGS_PASID; + + piotlb_info.domain_id = domain_id; + piotlb_info.pasid = pasid; + piotlb_info.stage1_cache = stage1_cache; + + 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(stage1_cache); } 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; + DualIOMMUStage1Cache *stage1_cache; + struct iommu_cache_invalidate_info *cache_info; + + stage1_cache = g_malloc0(sizeof(*stage1_cache)); + stage1_cache->pasid = pasid; + + cache_info = &stage1_cache->cache_info; + cache_info->version = IOMMU_UAPI_VERSION; + cache_info->cache = IOMMU_CACHE_INV_TYPE_IOTLB; + cache_info->granularity = IOMMU_INV_GRANU_ADDR; + cache_info->addr_info.flags = IOMMU_INV_ADDR_FLAGS_PASID; + cache_info->addr_info.flags |= ih ? IOMMU_INV_ADDR_FLAGS_LEAF : 0; + cache_info->addr_info.pasid = pasid; + cache_info->addr_info.addr = addr; + cache_info->addr_info.granule_size = 1 << (12 + am); + cache_info->addr_info.nb_granules = 1; + + piotlb_info.domain_id = domain_id; + piotlb_info.pasid = pasid; + piotlb_info.stage1_cache = stage1_cache; + + 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(stage1_cache); } 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 314e2c4..967cc4f 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -560,6 +560,13 @@ struct VTDPASIDCacheInfo { VTD_PASID_CACHE_DEVSI) typedef struct VTDPASIDCacheInfo VTDPASIDCacheInfo; +struct VTDPIOTLBInvInfo { + uint16_t domain_id; + uint32_t pasid; + DualIOMMUStage1Cache *stage1_cache; +}; +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 Sun Mar 22 12:36:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451757 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 55ACB6CA for ; Sun, 22 Mar 2020 12:36:02 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 34E3A206F8 for ; Sun, 22 Mar 2020 12:36:02 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 34E3A206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45998 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzph-0001X8-DO for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:36:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:48125) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzlA-0001Zw-7N for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzl9-00043B-2j for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:20 -0400 Received: from mga02.intel.com ([134.134.136.20]:41735) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzl8-0003ol-RB for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:19 -0400 IronPort-SDR: E8ZU+OpblzQfoiKR9Ph/8pR65dMWpXDHRHRkYBOrcrr1G6QXeGbzRHoc2hzLKugSxUr+fu39DE Hi4Wnw3apgxQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: RZemJe0dwmGxQDq4Bje/0PhqeQcXW2oLaZjP6z1E7e1wvoynXitZZqhaLZ9QwGtpvd5PtNpG3t cZgkVFBr1Qiw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664418" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 21/22] intel_iommu: process PASID-based Device-TLB invalidation Date: Sun, 22 Mar 2020 05:36:18 -0700 Message-Id: <1584880579-12178-22-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 Signed-off-by: Liu Yi L Reviewed-by: Peter Xu --- 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 10d314d..72cd739 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3339,6 +3339,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) { @@ -3460,6 +3471,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 967cc4f..b5507ce 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -386,6 +386,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 Sun Mar 22 12:36:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi Liu X-Patchwork-Id: 11451775 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8ED5C6CA for ; Sun, 22 Mar 2020 12:42:01 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 6E19A206F8 for ; Sun, 22 Mar 2020 12:42:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6E19A206F8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:46091 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzvU-0002G3-Kj for patchwork-qemu-devel@patchwork.kernel.org; Sun, 22 Mar 2020 08:42:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:48142) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jFzlB-0001dm-Mz for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jFzlA-00043e-8y for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:21 -0400 Received: from mga02.intel.com ([134.134.136.20]:41767) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jFzlA-0003tR-0a for qemu-devel@nongnu.org; Sun, 22 Mar 2020 08:31:20 -0400 IronPort-SDR: YAnWQCMLxnBbKZ220hxnEORrGpBMIswslAHcp/B2YDsh0xVpfYdL2cFikXiRpoDvlvVNEGRNrg ObkdT4ABWZtA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Mar 2020 05:30:39 -0700 IronPort-SDR: TqN52bRSjnvvxsJU9jEyhf9F6AUdxuzgn8JbCwADbsX4jobHLI9Hl99PYtlMexBJmCJe5B648c /DPisq9NwYVw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,292,1580803200"; d="scan'208";a="239664421" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga008.jf.intel.com with ESMTP; 22 Mar 2020 05:30:38 -0700 From: Liu Yi L To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com Subject: [PATCH v1 22/22] intel_iommu: modify x-scalable-mode to be string option Date: Sun, 22 Mar 2020 05:36:19 -0700 Message-Id: <1584880579-12178-23-git-send-email-yi.l.liu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> References: <1584880579-12178-1-git-send-email-yi.l.liu@intel.com> X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 134.134.136.20 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, hao.wu@intel.com, Richard Henderson , david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.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 Signed-off-by: Liu Yi L Signed-off-by: Yi Sun --- hw/i386/intel_iommu.c | 29 +++++++++++++++++++++++++++-- hw/i386/intel_iommu_internal.h | 4 ++++ include/hw/i386/intel_iommu.h | 2 ++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 72cd739..ea1f5c4 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4171,7 +4171,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(), }; @@ -4802,8 +4802,12 @@ 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_ECAP_VCS; + s->vccap |= VTD_VCCAP_PAS; } vtd_reset_caches(s); @@ -4935,6 +4939,27 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) return false; } + if (s->scalable_mode_str && + (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")) { + 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 b5507ce..52b25ff 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -196,8 +196,12 @@ #define VTD_ECAP_PT (1ULL << 6) #define VTD_ECAP_MHMV (15ULL << 20) #define VTD_ECAP_SRS (1ULL << 31) +#define VTD_ECAP_PSS (19ULL << 35) +#define VTD_ECAP_PASID (1ULL << 40) #define VTD_ECAP_SMTS (1ULL << 43) +#define VTD_ECAP_VCS (1ULL << 44) #define VTD_ECAP_SLTS (1ULL << 46) +#define VTD_ECAP_FLTS (1ULL << 47) /* CAP_REG */ /* (offset >> 4) << 24 */ diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 9782ac4..07494d4 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -268,6 +268,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) */