qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Liu, Yi L" <yi.l.liu@linux.intel.com>
To: qemu-devel@nongnu.org, alex.williamson@redhat.com, peterx@redhat.com
Cc: kvm@vger.kernel.org, jasowang@redhat.com,
	iommu@lists.linux-foundation.org, kevin.tian@intel.com,
	ashok.raj@intel.com, jacob.jun.pan@intel.com,
	tianyu.lan@intel.com, yi.l.liu@intel.com,
	jean-philippe.brucker@arm.com, "Liu,
	Yi L" <yi.l.liu@linux.intel.com>
Subject: [Qemu-devel] [RFC PATCH 15/20] intel_iommu: link whole guest pasid table to host
Date: Wed, 26 Apr 2017 18:06:45 +0800	[thread overview]
Message-ID: <1493201210-14357-16-git-send-email-yi.l.liu@linux.intel.com> (raw)
In-Reply-To: <1493201210-14357-1-git-send-email-yi.l.liu@linux.intel.com>

VT-d has a nested mode which allows SVM virtualization. Link the whole
guest PASID table to host context entry and enable nested mode, pIOMMU
would do nested translation for DMA request. Thus achieve GVA->HPA
translation.

When extended-context-entry is modified in guest, intel_iommu emulator
should capture it, then link the whole guest PASID table to host and
enable nested mode for the assigned device.

Signed-off-by: Liu, Yi L <yi.l.liu@linux.intel.com>
---
 hw/i386/intel_iommu.c          | 121 +++++++++++++++++++++++++++++++++++++++--
 hw/i386/intel_iommu_internal.h |  11 ++++
 2 files changed, 127 insertions(+), 5 deletions(-)

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index f291995..cd6db65 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -36,6 +36,7 @@
 #include "hw/i386/apic_internal.h"
 #include "kvm_i386.h"
 #include "trace.h"
+#include <linux/iommu.h>
 
 /*#define DEBUG_INTEL_IOMMU*/
 #ifdef DEBUG_INTEL_IOMMU
@@ -55,6 +56,14 @@ static int vtd_dbgflags = VTD_DBGBIT(GENERAL) | VTD_DBGBIT(CSR);
 #define VTD_DPRINTF(what, fmt, ...) do {} while (0)
 #endif
 
+typedef void (*vtd_device_hook)(VTDNotifierIterator *iter,
+                                void *hook_info,
+                                void *notify_info);
+
+static void vtd_context_inv_notify_hook(VTDNotifierIterator *iter,
+                                        void *hook_info,
+                                        void *notify_info);
+
 #define FOR_EACH_ASSIGN_DEVICE(__notify_info_type, \
                                __opaque_type, \
                                __hook_info, \
@@ -1213,6 +1222,66 @@ static void vtd_iommu_replay_all(IntelIOMMUState *s)
     }
 }
 
+void vtd_context_inv_notify_hook(VTDNotifierIterator *iter,
+                                 void *hook_info,
+                                 void *notify_info)
+{
+    struct pasid_table_info *pasidt_info;
+    IOMMUNotifierData iommu_data;
+    VTDContextHookInfo *context_hook_info;
+    uint16_t *host_sid;
+    pasidt_info = (struct pasid_table_info *) notify_info;
+    context_hook_info = (VTDContextHookInfo *) hook_info;
+    switch (context_hook_info->gran) {
+    case VTD_INV_DESC_CC_GLOBAL:
+        /* Fall through */
+    case VTD_INV_DESC_CC_DOMAIN:
+        if (iter->did == *context_hook_info->did) {
+            break;
+        }
+        /* Fall through */
+    case VTD_INV_DESC_CC_DEVICE:
+        if ((iter->did == *context_hook_info->did) &&
+            (iter->sid == *context_hook_info->sid)) {
+            break;
+        }
+        /* Fall through */
+    default:
+        return;
+    }
+
+    pasidt_info->model = INTEL_IOMMU;
+    host_sid = (uint16_t *)&pasidt_info->opaque;
+
+    pasidt_info->ptr = iter->ce[1].lo;
+    pasidt_info->size = iter->ce[1].lo & VTD_PASID_TABLE_SIZE_MASK;
+    *host_sid = iter->host_sid;
+    iommu_data.payload = (uint8_t *) pasidt_info;
+    iommu_data.payload_size = sizeof(*pasidt_info) + sizeof(*host_sid);
+    memory_region_notify_iommu_svm_bind(&iter->vtd_as->iommu,
+                                        &iommu_data);
+    return;
+}
+
+static void vtd_context_cache_invalidate_notify(IntelIOMMUState *s,
+                                                uint16_t *did,
+                                                uint16_t *sid,
+                                                uint8_t gran,
+                                                vtd_device_hook hook_fn)
+{
+    VTDContextHookInfo context_hook_info = {
+        .did = did,
+        .sid = sid,
+        .gran = gran,
+    };
+
+    FOR_EACH_ASSIGN_DEVICE(struct pasid_table_info,
+                           uint16_t,
+                           &context_hook_info,
+                           hook_fn);
+    return;
+}
+
 static void vtd_context_global_invalidate(IntelIOMMUState *s)
 {
     trace_vtd_inv_desc_cc_global();
@@ -1228,8 +1297,35 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s)
      * VT-d emulation codes.
      */
     vtd_iommu_replay_all(s);
+
+    if (s->svm) {
+        vtd_context_cache_invalidate_notify(s, NULL, NULL,
+                VTD_INV_DESC_CC_GLOBAL, vtd_context_inv_notify_hook);
+    }
 }
 
+static void vtd_context_domain_selective_invalidate(IntelIOMMUState *s,
+                                                    uint16_t did)
+{
+    trace_vtd_inv_desc_cc_global();
+    s->context_cache_gen++;
+    if (s->context_cache_gen == VTD_CONTEXT_CACHE_GEN_MAX) {
+        vtd_reset_context_cache(s);
+    }
+    /*
+     * From VT-d spec 6.5.2.1, a global context entry invalidation
+     * should be followed by a IOTLB global invalidation, so we should
+     * be safe even without this. Hoewever, let's replay the region as
+     * well to be safer, and go back here when we need finer tunes for
+     * VT-d emulation codes.
+     */
+    vtd_iommu_replay_all(s);
+
+    if (s->svm) {
+        vtd_context_cache_invalidate_notify(s, &did, NULL,
+                 VTD_INV_DESC_CC_DOMAIN, vtd_context_inv_notify_hook);
+    }
+}
 
 /* Find the VTD address space currently associated with a given bus number,
  */
@@ -1258,13 +1354,14 @@ static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num)
  */
 static void vtd_context_device_invalidate(IntelIOMMUState *s,
                                           uint16_t source_id,
+                                          uint16_t did,
                                           uint16_t func_mask)
 {
     uint16_t mask;
     VTDBus *vtd_bus;
     VTDAddressSpace *vtd_as;
     uint8_t bus_n, devfn;
-    uint16_t devfn_it;
+    uint16_t devfn_it, sid_it;
 
     trace_vtd_inv_desc_cc_devices(source_id, func_mask);
 
@@ -1311,6 +1408,12 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s,
                  * happened.
                  */
                 memory_region_iommu_replay_all(&vtd_as->iommu);
+                if (s->svm) {
+                    sid_it = vtd_make_source_id(pci_bus_num(vtd_bus->bus),
+                                                devfn_it);
+                    vtd_context_cache_invalidate_notify(s, &did, &sid_it,
+                        VTD_INV_DESC_CC_DEVICE, vtd_context_inv_notify_hook);
+                }
             }
         }
     }
@@ -1324,6 +1427,7 @@ static uint64_t vtd_context_cache_invalidate(IntelIOMMUState *s, uint64_t val)
 {
     uint64_t caig;
     uint64_t type = val & VTD_CCMD_CIRG_MASK;
+    uint16_t did;
 
     switch (type) {
     case VTD_CCMD_DOMAIN_INVL:
@@ -1338,7 +1442,9 @@ static uint64_t vtd_context_cache_invalidate(IntelIOMMUState *s, uint64_t val)
 
     case VTD_CCMD_DEVICE_INVL:
         caig = VTD_CCMD_DEVICE_INVL_A;
-        vtd_context_device_invalidate(s, VTD_CCMD_SID(val), VTD_CCMD_FM(val));
+        did = VTD_CCMD_DID(val);
+        vtd_context_device_invalidate(s, VTD_CCMD_SID(val),
+                                      did, VTD_CCMD_FM(val));
         break;
 
     default:
@@ -1720,7 +1826,7 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
 static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
                                            VTDInvDesc *inv_desc)
 {
-    uint16_t sid, fmask;
+    uint16_t sid, fmask, did;
 
     if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) {
         trace_vtd_inv_desc_cc_invalid(inv_desc->hi, inv_desc->lo);
@@ -1728,17 +1834,22 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
     }
     switch (inv_desc->lo & VTD_INV_DESC_CC_G) {
     case VTD_INV_DESC_CC_DOMAIN:
+        did = VTD_INV_DESC_CC_DID(inv_desc->lo);
+        vtd_context_domain_selective_invalidate(s, did);
         trace_vtd_inv_desc_cc_domain(
             (uint16_t)VTD_INV_DESC_CC_DID(inv_desc->lo));
-        /* Fall through */
+        break;
     case VTD_INV_DESC_CC_GLOBAL:
+        trace_vtd_inv_desc_cc_domain(
+            (uint16_t)VTD_INV_DESC_CC_DID(inv_desc->lo));
         vtd_context_global_invalidate(s);
         break;
 
     case VTD_INV_DESC_CC_DEVICE:
         sid = VTD_INV_DESC_CC_SID(inv_desc->lo);
         fmask = VTD_INV_DESC_CC_FM(inv_desc->lo);
-        vtd_context_device_invalidate(s, sid, fmask);
+        did = VTD_INV_DESC_CC_DID(inv_desc->lo);
+        vtd_context_device_invalidate(s, sid, did, fmask);
         break;
 
     default:
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index 5178398..5ab7d77 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -439,6 +439,14 @@ typedef struct VTDRootEntry VTDRootEntry;
 #define VTD_EXT_CONTEXT_TT_NO_DEV_IOTLB   (4ULL << 2)
 #define VTD_EXT_CONTEXT_TT_DEV_IOTLB      (5ULL << 2)
 
+struct VTDContextHookInfo {
+    uint16_t *did;
+    uint16_t *sid;
+    uint8_t  gran;
+};
+
+typedef struct VTDContextHookInfo VTDContextHookInfo;
+
 struct VTDNotifierIterator {
     VTDAddressSpace *vtd_as;
     VTDContextEntry *ce;
@@ -450,6 +458,9 @@ struct VTDNotifierIterator {
 
 typedef struct VTDNotifierIterator VTDNotifierIterator;
 
+/* Masks for struct VTDContextEntry - Extended Context */
+#define VTD_PASID_TABLE_SIZE_MASK 0xf
+
 /* Paging Structure common */
 #define VTD_SL_PT_PAGE_SIZE_MASK    (1ULL << 7)
 /* Bits to decide the offset for each level */
-- 
1.9.1

  parent reply	other threads:[~2017-04-26 10:24 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-26 10:06 [Qemu-devel] [RFC PATCH 00/20] Qemu: Extend intel_iommu emulator to support Shared Virtual Memory Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 01/20] intel_iommu: add "ecs" option Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 02/20] intel_iommu: exposed extended-context mode to guest Liu, Yi L
2017-04-27 10:32   ` Peter Xu
2017-04-28  6:00     ` Lan Tianyu
2017-04-28  9:56       ` Liu, Yi L
2017-04-28  9:55     ` Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 03/20] intel_iommu: add "svm" option Liu, Yi L
2017-04-27 10:53   ` Peter Xu
2017-05-04 20:28     ` Alex Williamson
2017-05-04 20:37       ` Raj, Ashok
2017-05-08 10:38     ` Liu, Yi L
2017-05-08 11:20       ` Peter Xu
2017-05-08  8:15         ` Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 04/20] Memory: modify parameter in IOMMUNotifier func Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 05/20] VFIO: add new IOCTL for svm bind tasks Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 06/20] VFIO: add new notifier for binding PASID table Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 07/20] VFIO: check notifier flag in region_del() Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 08/20] Memory: add notifier flag check in memory_replay() Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 09/20] Memory: introduce iommu_ops->record_device Liu, Yi L
2017-04-28  6:46   ` Lan Tianyu
2017-05-19  5:23     ` Liu, Yi L
2017-05-19  9:07       ` Tian, Kevin
2017-05-19  9:35         ` Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 10/20] VFIO: notify vIOMMU emulator when device is assigned Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 11/20] intel_iommu: provide iommu_ops->record_device Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 12/20] Memory: Add func to fire pasidt_bind notifier Liu, Yi L
2017-04-26 13:50   ` Paolo Bonzini
2017-04-27  2:37     ` Liu, Yi L
2017-04-27  6:14       ` Peter Xu
2017-04-27 10:09         ` Peter Xu
2017-04-27 10:25         ` Liu, Yi L
2017-04-27 10:51           ` Peter Xu
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 13/20] IOMMU: add pasid_table_info for guest pasid table Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 14/20] intel_iommu: add FOR_EACH_ASSIGN_DEVICE macro Liu, Yi L
2017-04-28  7:33   ` Lan Tianyu
2017-04-26 10:06 ` Liu, Yi L [this message]
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 16/20] VFIO: Add notifier for propagating IOMMU TLB invalidate Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 17/20] Memory: Add func to fire TLB invalidate notifier Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 18/20] intel_iommu: propagate Extended-IOTLB invalidate to host Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 19/20] intel_iommu: propagate PASID-Cache " Liu, Yi L
2017-04-26 10:06 ` [Qemu-devel] [RFC PATCH 20/20] intel_iommu: propagate Ext-Device-TLB " 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=1493201210-14357-16-git-send-email-yi.l.liu@linux.intel.com \
    --to=yi.l.liu@linux.intel.com \
    --cc=alex.williamson@redhat.com \
    --cc=ashok.raj@intel.com \
    --cc=iommu@lists.linux-foundation.org \
    --cc=jacob.jun.pan@intel.com \
    --cc=jasowang@redhat.com \
    --cc=jean-philippe.brucker@arm.com \
    --cc=kevin.tian@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=peterx@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=tianyu.lan@intel.com \
    --cc=yi.l.liu@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).