kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Liu Yi L <yi.l.liu@intel.com>
To: qemu-devel@nongnu.org, mst@redhat.com, pbonzini@redhat.com,
	alex.williamson@redhat.com, peterx@redhat.com
Cc: eric.auger@redhat.com, david@gibson.dropbear.id.au,
	tianyu.lan@intel.com, kevin.tian@intel.com, yi.l.liu@intel.com,
	jun.j.tian@intel.com, yi.y.sun@intel.com, kvm@vger.kernel.org,
	Jacob Pan <jacob.jun.pan@linux.intel.com>,
	Yi Sun <yi.y.sun@linux.intel.com>
Subject: [RFC v1 12/18] intel_iommu: bind/unbind guest page table to host
Date: Fri,  5 Jul 2019 19:01:45 +0800	[thread overview]
Message-ID: <1562324511-2910-13-git-send-email-yi.l.liu@intel.com> (raw)
In-Reply-To: <1562324511-2910-1-git-send-email-yi.l.liu@intel.com>

This patch captures the guest PASID table entry modifications and passdown
the changes to host. Thus guest page table is bound to host IOMMU and 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 key part of vSVA support in KVM.

Cc: Kevin Tian <kevin.tian@intel.com>
Cc: Jacob Pan <jacob.jun.pan@linux.intel.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Yi Sun <yi.y.sun@linux.intel.com>
Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
---
 hw/i386/intel_iommu.c          | 85 +++++++++++++++++++++++++++++++++++++++++-
 hw/i386/intel_iommu_internal.h | 20 ++++++++++
 2 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index cfe5dbf..d897a52 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -703,6 +703,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_pe_present(VTDPASIDEntry *pe)
 {
     return pe->val[0] & VTD_PASID_ENTRY_P;
@@ -1836,6 +1846,47 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s)
     vtd_iommu_replay_all(s);
 }
 
+static void vtd_bind_guest_pasid(IntelIOMMUState *s, int bus_n,
+            int devfn, int pasid, VTDPASIDEntry *pe, VTDPASIDOp op)
+{
+    PCIBus *bus;
+    struct gpasid_bind_data *g_bind_data;
+    bus = vtd_find_pci_bus_from_bus_num(s, bus_n);
+    g_bind_data = g_malloc0(sizeof(*g_bind_data));
+
+    switch (op) {
+    case VTD_PASID_BIND:
+    case VTD_PASID_UPDATE:
+        g_bind_data->version = IOMMU_GPASID_BIND_VERSION_1;
+        g_bind_data->format = IOMMU_PASID_FORMAT_INTEL_VTD;
+        g_bind_data->gpgd = vtd_pe_get_flpt_base(pe);
+        g_bind_data->addr_width = vtd_pe_get_fl_aw(pe);
+        g_bind_data->hpasid = pasid;
+        g_bind_data->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]);
+        pci_device_bind_gpasid(bus, devfn, g_bind_data);
+        break;
+
+    case VTD_PASID_UNBIND:
+        g_bind_data->gpgd = 0;
+        g_bind_data->addr_width = 0;
+        g_bind_data->hpasid = pasid;
+        pci_device_unbind_gpasid(bus, devfn, g_bind_data);
+        break;
+
+    default:
+        printf("Unknown VTDPASIDOp!!\n");
+        break;
+    }
+}
+
 /* Do a context-cache device-selective invalidation.
  * @func_mask: FM field after shifting
  */
@@ -1893,6 +1944,17 @@ 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. Here, mark it as a TODO.
+                 * 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
+                 */
             }
         }
     }
@@ -3636,7 +3698,7 @@ static gboolean vtd_flush_pasid(gpointer key, gpointer value,
 {
     VTDPASIDCacheInfo *pc_info = user_data;
     VTDAddressSpace *vtd_pasid_as = value;
-    uint16_t did;
+    uint16_t did, devfn;
     uint32_t pasid;
 
     if (!vtd_pasid_as || !vtd_pasid_as->pasid_allocated) {
@@ -3645,6 +3707,7 @@ static gboolean vtd_flush_pasid(gpointer key, gpointer value,
 
     did = vtd_pe_get_domain_id(&(vtd_pasid_as->pasid_cache_entry.pasid_entry));
     pasid = vtd_pasid_as->pasid;
+    devfn = vtd_pasid_as->devfn;
     if (vtd_pasid_as->pasid_cache_entry.pasid_cache_gen &&
         (vtd_pc_is_dom_si(pc_info) ? (pc_info->domain_id == did) : 1) &&
         (vtd_pc_is_pasid_si(pc_info) ? (pc_info->pasid == pasid) : 1)) {
@@ -3655,6 +3718,19 @@ static gboolean vtd_flush_pasid(gpointer key, gpointer value,
          * cache gen is updated in a new pasid binding.
          */
         vtd_pasid_as->pasid_cache_entry.pasid_cache_gen = 0;
+        /*
+         * To be clean, invalidate the vtd_pasid_as instance is expected.
+         * but it is optional if wants to save memory allocation for
+         * frequent pasid usage on a device. This function will not
+         * release the vtd_pasid_as instance, the caller should do
+         * it explicitly.
+         */
+        vtd_bind_guest_pasid(vtd_pasid_as->iommu_state,
+                             pci_bus_num(vtd_pasid_as->bus),
+                             devfn,
+                             pasid,
+                             NULL,
+                             VTD_PASID_UNBIND);
         return true;
     }
 
@@ -3824,11 +3900,18 @@ static int vtd_pasid_cache_psi(IntelIOMMUState *s,
                                              devfn, pasid, true);
             if (!vtd_pasid_as) {
                 printf("%s, fatal error happened!\n", __func__);
+                /*
+                 * get vtd_pasid_as failed, need to do an unbind
+                 * in case of previous bind
+                 */
+                vtd_bind_guest_pasid(s, bus_n, devfn,
+                                     pasid, NULL, VTD_PASID_UNBIND);
                 continue;
             }
             pc_entry = &vtd_pasid_as->pasid_cache_entry;
             pc_entry->pasid_entry = pe; /* update pasid cache */
             pc_entry->pasid_cache_gen = s->pasid_cache_gen;
+            vtd_bind_guest_pasid(s, bus_n, devfn, pasid, &pe, VTD_PASID_BIND);
         }
     }
     return 0;
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index afeb6aa..f9a4ac6 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -474,6 +474,14 @@ struct VTDRootEntry {
 };
 typedef struct VTDRootEntry VTDRootEntry;
 
+enum VTDPASIDOp {
+    VTD_PASID_BIND,
+    VTD_PASID_UNBIND,
+    VTD_PASID_UPDATE,
+    VTD_OP_NUM
+};
+typedef enum VTDPASIDOp VTDPASIDOp;
+
 struct VTDPASIDCacheInfo {
 #define VTD_PASID_CACHE_DOMSI   (1ULL << 0);
 #define VTD_PASID_CACHE_PASIDSI (1ULL << 1);
@@ -540,6 +548,18 @@ 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)
 
+/* Adjusted guest-address-width */
+#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)
 
-- 
2.7.4


  parent reply	other threads:[~2019-07-06 11:19 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-05 11:01 [RFC v1 00/18] intel_iommu: expose Shared Virtual Addressing to VM Liu Yi L
2019-07-05 11:01 ` [RFC v1 01/18] linux-headers: import iommu.h from kernel Liu Yi L
2019-07-05 11:01 ` [RFC v1 02/18] linux-headers: import vfio.h " Liu Yi L
2019-07-09  1:58   ` Peter Xu
2019-07-09  8:37     ` Auger Eric
2019-07-10 12:31       ` Liu, Yi L
2019-07-10 12:29     ` Liu, Yi L
2019-07-05 11:01 ` [RFC v1 03/18] hw/pci: introduce PCIPASIDOps to PCIDevice Liu Yi L
2019-07-09  2:12   ` Peter Xu
2019-07-09 10:41     ` Auger Eric
2019-07-10 11:08     ` Liu, Yi L
2019-07-11  3:51       ` david
2019-07-11  7:13         ` Liu, Yi L
2019-07-05 11:01 ` [RFC v1 04/18] intel_iommu: add "sm_model" option Liu Yi L
2019-07-09  2:15   ` Peter Xu
2019-07-10 12:14     ` Liu, Yi L
2019-07-11  1:03       ` Peter Xu
2019-07-11  6:25         ` Liu, Yi L
2019-07-05 11:01 ` [RFC v1 05/18] vfio/pci: add pasid alloc/free implementation Liu Yi L
2019-07-09  2:23   ` Peter Xu
2019-07-10 12:16     ` Liu, Yi L
2019-07-15  2:55   ` David Gibson
2019-07-16 10:25     ` Liu, Yi L
2019-07-17  3:06       ` David Gibson
2019-07-22  7:02         ` Liu, Yi L
2019-07-23  3:57           ` David Gibson
2019-07-24  4:57             ` Liu, Yi L
2019-07-24  9:33               ` Auger Eric
2019-07-25  3:40                 ` David Gibson
2019-07-26  5:18                 ` Liu, Yi L
2019-08-02  7:36                   ` Auger Eric
2019-07-05 11:01 ` [RFC v1 06/18] intel_iommu: support virtual command emulation and pasid request Liu Yi L
2019-07-09  3:19   ` Peter Xu
2019-07-10 11:51     ` Liu, Yi L
2019-07-11  1:13       ` Peter Xu
2019-07-11  6:59         ` Liu, Yi L
2019-07-05 11:01 ` [RFC v1 07/18] hw/pci: add pci_device_bind/unbind_gpasid Liu Yi L
2019-07-09  8:37   ` Auger Eric
2019-07-10 12:18     ` Liu, Yi L
2019-07-05 11:01 ` [RFC v1 08/18] vfio/pci: add vfio bind/unbind_gpasid implementation Liu Yi L
2019-07-09  8:37   ` Auger Eric
2019-07-10 12:30     ` Liu, Yi L
2019-07-05 11:01 ` [RFC v1 09/18] intel_iommu: process pasid cache invalidation Liu Yi L
2019-07-09  4:47   ` Peter Xu
2019-07-11  6:22     ` Liu, Yi L
2019-07-05 11:01 ` [RFC v1 10/18] intel_iommu: tag VTDAddressSpace instance with PASID Liu Yi L
2019-07-09  6:12   ` Peter Xu
2019-07-11  7:24     ` Liu, Yi L
2019-07-05 11:01 ` [RFC v1 11/18] intel_iommu: create VTDAddressSpace per BDF+PASID Liu Yi L
2019-07-09  6:39   ` Peter Xu
2019-07-11  8:13     ` Liu, Yi L
2019-07-05 11:01 ` Liu Yi L [this message]
2019-07-05 11:01 ` [RFC v1 13/18] intel_iommu: flush pasid cache after a DSI context cache flush Liu Yi L
2019-07-05 11:01 ` [RFC v1 14/18] hw/pci: add flush_pasid_iotlb() in PCIPASIDOps Liu Yi L
2019-07-05 11:01 ` [RFC v1 15/18] vfio/pci: adds support for PASID-based iotlb flush Liu Yi L
2019-07-05 11:01 ` [RFC v1 16/18] intel_iommu: add PASID-based iotlb invalidation support Liu Yi L
2019-07-05 11:01 ` [RFC v1 17/18] intel_iommu: propagate PASID-based iotlb flush to host Liu Yi L
2019-07-05 11:01 ` [RFC v1 18/18] intel_iommu: do not passdown pasid bind for PASID #0 Liu Yi L

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1562324511-2910-13-git-send-email-yi.l.liu@intel.com \
    --to=yi.l.liu@intel.com \
    --cc=alex.williamson@redhat.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=eric.auger@redhat.com \
    --cc=jacob.jun.pan@linux.intel.com \
    --cc=jun.j.tian@intel.com \
    --cc=kevin.tian@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=mst@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=peterx@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=tianyu.lan@intel.com \
    --cc=yi.y.sun@intel.com \
    --cc=yi.y.sun@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).