|
|
76daa3 |
From 00c6524796e9fcbcf21804f24f84b835fd667498 Mon Sep 17 00:00:00 2001
|
|
|
76daa3 |
From: Peter Xu <peterx@redhat.com>
|
|
|
76daa3 |
Date: Mon, 24 Apr 2017 02:52:52 +0200
|
|
|
76daa3 |
Subject: [PATCH 13/23] intel_iommu: allow dynamic switch of IOMMU region
|
|
|
76daa3 |
|
|
|
76daa3 |
RH-Author: Peter Xu <peterx@redhat.com>
|
|
|
76daa3 |
Message-id: <1493002373-13010-9-git-send-email-peterx@redhat.com>
|
|
|
76daa3 |
Patchwork-id: 74856
|
|
|
76daa3 |
O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH v2 8/9] intel_iommu: allow dynamic switch of IOMMU region
|
|
|
76daa3 |
Bugzilla: 1335808
|
|
|
76daa3 |
RH-Acked-by: Marcel Apfelbaum <marcel@redhat.com>
|
|
|
76daa3 |
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
76daa3 |
RH-Acked-by: Xiao Wang <jasowang@redhat.com>
|
|
|
76daa3 |
|
|
|
76daa3 |
This is preparation work to finally enabled dynamic switching ON/OFF for
|
|
|
76daa3 |
VT-d protection. The old VT-d codes is using static IOMMU address space,
|
|
|
76daa3 |
and that won't satisfy vfio-pci device listeners.
|
|
|
76daa3 |
|
|
|
76daa3 |
Let me explain.
|
|
|
76daa3 |
|
|
|
76daa3 |
vfio-pci devices depend on the memory region listener and IOMMU replay
|
|
|
76daa3 |
mechanism to make sure the device mapping is coherent with the guest
|
|
|
76daa3 |
even if there are domain switches. And there are two kinds of domain
|
|
|
76daa3 |
switches:
|
|
|
76daa3 |
|
|
|
76daa3 |
(1) switch from domain A -> B
|
|
|
76daa3 |
(2) switch from domain A -> no domain (e.g., turn DMAR off)
|
|
|
76daa3 |
|
|
|
76daa3 |
Case (1) is handled by the context entry invalidation handling by the
|
|
|
76daa3 |
VT-d replay logic. What the replay function should do here is to replay
|
|
|
76daa3 |
the existing page mappings in domain B.
|
|
|
76daa3 |
|
|
|
76daa3 |
However for case (2), we don't want to replay any domain mappings - we
|
|
|
76daa3 |
just need the default GPA->HPA mappings (the address_space_memory
|
|
|
76daa3 |
mapping). And this patch helps on case (2) to build up the mapping
|
|
|
76daa3 |
automatically by leveraging the vfio-pci memory listeners.
|
|
|
76daa3 |
|
|
|
76daa3 |
Another important thing that this patch does is to seperate
|
|
|
76daa3 |
IR (Interrupt Remapping) from DMAR (DMA Remapping). IR region should not
|
|
|
76daa3 |
depend on the DMAR region (like before this patch). It should be a
|
|
|
76daa3 |
standalone region, and it should be able to be activated without
|
|
|
76daa3 |
DMAR (which is a common behavior of Linux kernel - by default it enables
|
|
|
76daa3 |
IR while disabled DMAR).
|
|
|
76daa3 |
|
|
|
76daa3 |
Reviewed-by: Jason Wang <jasowang@redhat.com>
|
|
|
76daa3 |
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
|
|
|
76daa3 |
Reviewed-by: \"Michael S. Tsirkin\" <mst@redhat.com>
|
|
|
76daa3 |
Signed-off-by: Peter Xu <peterx@redhat.com>
|
|
|
76daa3 |
Message-Id: <1491562755-23867-9-git-send-email-peterx@redhat.com>
|
|
|
76daa3 |
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
|
|
|
76daa3 |
(cherry picked from commit 558e0024a428a8f21605dc8aa026612ccc0f14cd)
|
|
|
76daa3 |
Signed-off-by: Peter Xu <peterx@redhat.com>
|
|
|
76daa3 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
76daa3 |
---
|
|
|
76daa3 |
hw/i386/intel_iommu.c | 81 ++++++++++++++++++++++++++++++++++++++++---
|
|
|
76daa3 |
hw/i386/trace-events | 2 +-
|
|
|
76daa3 |
include/hw/i386/intel_iommu.h | 2 ++
|
|
|
76daa3 |
3 files changed, 79 insertions(+), 6 deletions(-)
|
|
|
76daa3 |
|
|
|
76daa3 |
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
|
|
|
76daa3 |
index 7af4e22..f7dec82 100644
|
|
|
76daa3 |
--- a/hw/i386/intel_iommu.c
|
|
|
76daa3 |
+++ b/hw/i386/intel_iommu.c
|
|
|
76daa3 |
@@ -1291,9 +1291,49 @@ static void vtd_handle_gcmd_sirtp(IntelIOMMUState *s)
|
|
|
76daa3 |
vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_IRTPS);
|
|
|
76daa3 |
}
|
|
|
76daa3 |
|
|
|
76daa3 |
+static void vtd_switch_address_space(VTDAddressSpace *as)
|
|
|
76daa3 |
+{
|
|
|
76daa3 |
+ assert(as);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ trace_vtd_switch_address_space(pci_bus_num(as->bus),
|
|
|
76daa3 |
+ VTD_PCI_SLOT(as->devfn),
|
|
|
76daa3 |
+ VTD_PCI_FUNC(as->devfn),
|
|
|
76daa3 |
+ as->iommu_state->dmar_enabled);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ /* Turn off first then on the other */
|
|
|
76daa3 |
+ if (as->iommu_state->dmar_enabled) {
|
|
|
76daa3 |
+ memory_region_set_enabled(&as->sys_alias, false);
|
|
|
76daa3 |
+ memory_region_set_enabled(&as->iommu, true);
|
|
|
76daa3 |
+ } else {
|
|
|
76daa3 |
+ memory_region_set_enabled(&as->iommu, false);
|
|
|
76daa3 |
+ memory_region_set_enabled(&as->sys_alias, true);
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+}
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+static void vtd_switch_address_space_all(IntelIOMMUState *s)
|
|
|
76daa3 |
+{
|
|
|
76daa3 |
+ GHashTableIter iter;
|
|
|
76daa3 |
+ VTDBus *vtd_bus;
|
|
|
76daa3 |
+ int i;
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ g_hash_table_iter_init(&iter, s->vtd_as_by_busptr);
|
|
|
76daa3 |
+ while (g_hash_table_iter_next(&iter, NULL, (void **)&vtd_bus)) {
|
|
|
76daa3 |
+ for (i = 0; i < X86_IOMMU_PCI_DEVFN_MAX; i++) {
|
|
|
76daa3 |
+ if (!vtd_bus->dev_as[i]) {
|
|
|
76daa3 |
+ continue;
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+ vtd_switch_address_space(vtd_bus->dev_as[i]);
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+}
|
|
|
76daa3 |
+
|
|
|
76daa3 |
/* Handle Translation Enable/Disable */
|
|
|
76daa3 |
static void vtd_handle_gcmd_te(IntelIOMMUState *s, bool en)
|
|
|
76daa3 |
{
|
|
|
76daa3 |
+ if (s->dmar_enabled == en) {
|
|
|
76daa3 |
+ return;
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+
|
|
|
76daa3 |
VTD_DPRINTF(CSR, "Translation Enable %s", (en ? "on" : "off"));
|
|
|
76daa3 |
|
|
|
76daa3 |
if (en) {
|
|
|
76daa3 |
@@ -1308,6 +1348,8 @@ static void vtd_handle_gcmd_te(IntelIOMMUState *s, bool en)
|
|
|
76daa3 |
/* Ok - report back to driver */
|
|
|
76daa3 |
vtd_set_clear_mask_long(s, DMAR_GSTS_REG, VTD_GSTS_TES, 0);
|
|
|
76daa3 |
}
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ vtd_switch_address_space_all(s);
|
|
|
76daa3 |
}
|
|
|
76daa3 |
|
|
|
76daa3 |
/* Handle Interrupt Remap Enable/Disable */
|
|
|
76daa3 |
@@ -2529,15 +2571,44 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
|
|
|
76daa3 |
vtd_dev_as->devfn = (uint8_t)devfn;
|
|
|
76daa3 |
vtd_dev_as->iommu_state = s;
|
|
|
76daa3 |
vtd_dev_as->context_cache_entry.context_cache_gen = 0;
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ /*
|
|
|
76daa3 |
+ * Memory region relationships looks like (Address range shows
|
|
|
76daa3 |
+ * only lower 32 bits to make it short in length...):
|
|
|
76daa3 |
+ *
|
|
|
76daa3 |
+ * |-----------------+-------------------+----------|
|
|
|
76daa3 |
+ * | Name | Address range | Priority |
|
|
|
76daa3 |
+ * |-----------------+-------------------+----------+
|
|
|
76daa3 |
+ * | vtd_root | 00000000-ffffffff | 0 |
|
|
|
76daa3 |
+ * | intel_iommu | 00000000-ffffffff | 1 |
|
|
|
76daa3 |
+ * | vtd_sys_alias | 00000000-ffffffff | 1 |
|
|
|
76daa3 |
+ * | intel_iommu_ir | fee00000-feefffff | 64 |
|
|
|
76daa3 |
+ * |-----------------+-------------------+----------|
|
|
|
76daa3 |
+ *
|
|
|
76daa3 |
+ * We enable/disable DMAR by switching enablement for
|
|
|
76daa3 |
+ * vtd_sys_alias and intel_iommu regions. IR region is always
|
|
|
76daa3 |
+ * enabled.
|
|
|
76daa3 |
+ */
|
|
|
76daa3 |
memory_region_init_iommu(&vtd_dev_as->iommu, OBJECT(s),
|
|
|
76daa3 |
- &s->iommu_ops, "intel_iommu", UINT64_MAX);
|
|
|
76daa3 |
+ &s->iommu_ops, "intel_iommu_dmar",
|
|
|
76daa3 |
+ UINT64_MAX);
|
|
|
76daa3 |
+ memory_region_init_alias(&vtd_dev_as->sys_alias, OBJECT(s),
|
|
|
76daa3 |
+ "vtd_sys_alias", get_system_memory(),
|
|
|
76daa3 |
+ 0, memory_region_size(get_system_memory()));
|
|
|
76daa3 |
memory_region_init_io(&vtd_dev_as->iommu_ir, OBJECT(s),
|
|
|
76daa3 |
&vtd_mem_ir_ops, s, "intel_iommu_ir",
|
|
|
76daa3 |
VTD_INTERRUPT_ADDR_SIZE);
|
|
|
76daa3 |
- memory_region_add_subregion(&vtd_dev_as->iommu, VTD_INTERRUPT_ADDR_FIRST,
|
|
|
76daa3 |
- &vtd_dev_as->iommu_ir);
|
|
|
76daa3 |
- address_space_init(&vtd_dev_as->as,
|
|
|
76daa3 |
- &vtd_dev_as->iommu, name);
|
|
|
76daa3 |
+ memory_region_init(&vtd_dev_as->root, OBJECT(s),
|
|
|
76daa3 |
+ "vtd_root", UINT64_MAX);
|
|
|
76daa3 |
+ memory_region_add_subregion_overlap(&vtd_dev_as->root,
|
|
|
76daa3 |
+ VTD_INTERRUPT_ADDR_FIRST,
|
|
|
76daa3 |
+ &vtd_dev_as->iommu_ir, 64);
|
|
|
76daa3 |
+ address_space_init(&vtd_dev_as->as, &vtd_dev_as->root, name);
|
|
|
76daa3 |
+ memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
|
|
|
76daa3 |
+ &vtd_dev_as->sys_alias, 1);
|
|
|
76daa3 |
+ memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
|
|
|
76daa3 |
+ &vtd_dev_as->iommu, 1);
|
|
|
76daa3 |
+ vtd_switch_address_space(vtd_dev_as);
|
|
|
76daa3 |
}
|
|
|
76daa3 |
return vtd_dev_as;
|
|
|
76daa3 |
}
|
|
|
76daa3 |
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
|
|
|
76daa3 |
index f725bca..3c3a167 100644
|
|
|
76daa3 |
--- a/hw/i386/trace-events
|
|
|
76daa3 |
+++ b/hw/i386/trace-events
|
|
|
76daa3 |
@@ -4,7 +4,6 @@
|
|
|
76daa3 |
x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32
|
|
|
76daa3 |
|
|
|
76daa3 |
# hw/i386/intel_iommu.c
|
|
|
76daa3 |
-vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"
|
|
|
76daa3 |
vtd_inv_desc(const char *type, uint64_t hi, uint64_t lo) "invalidate desc type %s high 0x%"PRIx64" low 0x%"PRIx64
|
|
|
76daa3 |
vtd_inv_desc_invalid(uint64_t hi, uint64_t lo) "invalid inv desc hi 0x%"PRIx64" lo 0x%"PRIx64
|
|
|
76daa3 |
vtd_inv_desc_cc_domain(uint16_t domain) "context invalidate domain 0x%"PRIx16
|
|
|
76daa3 |
@@ -37,6 +36,7 @@ vtd_page_walk_one(uint32_t level, uint64_t iova, uint64_t gpa, uint64_t mask, in
|
|
|
76daa3 |
vtd_page_walk_skip_read(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to unable to read"
|
|
|
76daa3 |
vtd_page_walk_skip_perm(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to perm empty"
|
|
|
76daa3 |
vtd_page_walk_skip_reserve(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to rsrv set"
|
|
|
76daa3 |
+vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"
|
|
|
76daa3 |
|
|
|
76daa3 |
# hw/i386/amd_iommu.c
|
|
|
76daa3 |
amdvi_evntlog_fail(uint64_t addr, uint32_t head) "error: fail to write at addr 0x%"PRIx64" + offset 0x%"PRIx32
|
|
|
76daa3 |
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
|
|
|
76daa3 |
index fe645aa..8f212a1 100644
|
|
|
76daa3 |
--- a/include/hw/i386/intel_iommu.h
|
|
|
76daa3 |
+++ b/include/hw/i386/intel_iommu.h
|
|
|
76daa3 |
@@ -83,6 +83,8 @@ struct VTDAddressSpace {
|
|
|
76daa3 |
uint8_t devfn;
|
|
|
76daa3 |
AddressSpace as;
|
|
|
76daa3 |
MemoryRegion iommu;
|
|
|
76daa3 |
+ MemoryRegion root;
|
|
|
76daa3 |
+ MemoryRegion sys_alias;
|
|
|
76daa3 |
MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */
|
|
|
76daa3 |
IntelIOMMUState *iommu_state;
|
|
|
76daa3 |
VTDContextCacheEntry context_cache_entry;
|
|
|
76daa3 |
--
|
|
|
76daa3 |
1.8.3.1
|
|
|
76daa3 |
|