linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/4] thunderbolt: Make iommu_dma_protection more accurate
@ 2022-04-05 10:41 Robin Murphy
  2022-04-05 10:41 ` [PATCH v3 1/4] iommu: Introduce device_iommu_capable() Robin Murphy
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Robin Murphy @ 2022-04-05 10:41 UTC (permalink / raw)
  To: joro, baolu.lu, andreas.noever, michael.jamet, mika.westerberg,
	YehezkelShB
  Cc: iommu, linux-usb, linux-kernel, mario.limonciello, hch

Hi all,

Here's the third and hopefully final outing for this series, addressing
Mika's review comments from last time and taking advantage of 5.18-rc1
goodies to be even cleaner and more complete. I've also picked up
Mario's AMD IOMMU patch to keep the whole topic together.

Unless there's other pending Thunderbolt development which might
conflict, I suspect it would be simplest for the whole lot to go through
the IOMMU tree.

Thanks,
Robin.


Mario Limonciello (1):
  iommu/amd: Indicate whether DMA remap support is enabled

Robin Murphy (3):
  iommu: Introduce device_iommu_capable()
  iommu: Add capability for pre-boot DMA protection
  thunderbolt: Make iommu_dma_protection more accurate

 drivers/iommu/amd/amd_iommu_types.h         |  4 ++
 drivers/iommu/amd/init.c                    |  3 ++
 drivers/iommu/amd/iommu.c                   |  4 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  2 +-
 drivers/iommu/arm/arm-smmu/arm-smmu.c       |  2 +-
 drivers/iommu/arm/arm-smmu/qcom_iommu.c     |  2 +-
 drivers/iommu/fsl_pamu_domain.c             |  2 +-
 drivers/iommu/intel/iommu.c                 |  4 +-
 drivers/iommu/iommu.c                       | 25 +++++++++++-
 drivers/iommu/s390-iommu.c                  |  2 +-
 drivers/thunderbolt/domain.c                | 12 ++----
 drivers/thunderbolt/nhi.c                   | 44 +++++++++++++++++++++
 include/linux/iommu.h                       | 10 ++++-
 include/linux/thunderbolt.h                 |  2 +
 14 files changed, 100 insertions(+), 18 deletions(-)

-- 
2.28.0.dirty


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 1/4] iommu: Introduce device_iommu_capable()
  2022-04-05 10:41 [PATCH v3 0/4] thunderbolt: Make iommu_dma_protection more accurate Robin Murphy
@ 2022-04-05 10:41 ` Robin Murphy
  2022-04-06  5:28   ` Christoph Hellwig
  2022-04-05 10:41 ` [PATCH v3 2/4] iommu: Add capability for pre-boot DMA protection Robin Murphy
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Robin Murphy @ 2022-04-05 10:41 UTC (permalink / raw)
  To: joro, baolu.lu, andreas.noever, michael.jamet, mika.westerberg,
	YehezkelShB
  Cc: iommu, linux-usb, linux-kernel, mario.limonciello, hch

iommu_capable() only really works for systems where all IOMMU instances
are completely homogeneous, and all devices are IOMMU-mapped. Implement
the new variant which can give an accurate answer for whichever device
the caller is actually interested in.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---

v3: New patch; now that the dev_iommu_ops() work has landed we can go
    straight to a proper implementation. Also s/dev/device/ to match
    the precedent of device_iommu_mapped() for the public API.

 drivers/iommu/amd/iommu.c                   |  2 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  2 +-
 drivers/iommu/arm/arm-smmu/arm-smmu.c       |  2 +-
 drivers/iommu/arm/arm-smmu/qcom_iommu.c     |  2 +-
 drivers/iommu/fsl_pamu_domain.c             |  2 +-
 drivers/iommu/intel/iommu.c                 |  2 +-
 drivers/iommu/iommu.c                       | 25 ++++++++++++++++++++-
 drivers/iommu/s390-iommu.c                  |  2 +-
 include/linux/iommu.h                       |  8 ++++++-
 9 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 1160a13c80ab..e412a50dce59 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2132,7 +2132,7 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
 	return ops->iova_to_phys(ops, iova);
 }
 
-static bool amd_iommu_capable(enum iommu_cap cap)
+static bool amd_iommu_capable(struct device *dev, enum iommu_cap cap)
 {
 	switch (cap) {
 	case IOMMU_CAP_CACHE_COHERENCY:
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 73b7b1b17b77..b221525c31b9 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1981,7 +1981,7 @@ static const struct iommu_flush_ops arm_smmu_flush_ops = {
 };
 
 /* IOMMU API */
-static bool arm_smmu_capable(enum iommu_cap cap)
+static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap)
 {
 	switch (cap) {
 	case IOMMU_CAP_CACHE_COHERENCY:
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index f0bec4a35df5..34cab56b9c6d 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -1313,7 +1313,7 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
 	return ops->iova_to_phys(ops, iova);
 }
 
-static bool arm_smmu_capable(enum iommu_cap cap)
+static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap)
 {
 	switch (cap) {
 	case IOMMU_CAP_CACHE_COHERENCY:
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 80af00f468b4..028649203d33 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -493,7 +493,7 @@ static phys_addr_t qcom_iommu_iova_to_phys(struct iommu_domain *domain,
 	return ret;
 }
 
-static bool qcom_iommu_capable(enum iommu_cap cap)
+static bool qcom_iommu_capable(struct device *dev, enum iommu_cap cap)
 {
 	switch (cap) {
 	case IOMMU_CAP_CACHE_COHERENCY:
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index 7274f86b2bc4..ddf5ab28615c 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -177,7 +177,7 @@ static phys_addr_t fsl_pamu_iova_to_phys(struct iommu_domain *domain,
 	return iova;
 }
 
-static bool fsl_pamu_capable(enum iommu_cap cap)
+static bool fsl_pamu_capable(struct device *dev, enum iommu_cap cap)
 {
 	return cap == IOMMU_CAP_CACHE_COHERENCY;
 }
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 21111491ddfd..255304eb3b1f 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4544,7 +4544,7 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
 	return phys;
 }
 
-static bool intel_iommu_capable(enum iommu_cap cap)
+static bool intel_iommu_capable(struct device *dev, enum iommu_cap cap)
 {
 	if (cap == IOMMU_CAP_CACHE_COHERENCY)
 		return domain_update_iommu_snooping(NULL);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index efad7c1675e0..469574e84e6a 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1889,12 +1889,35 @@ static int iommu_bus_init(struct bus_type *bus)
 	return err;
 }
 
+/**
+ * device_iommu_capable() - check for a general IOMMU capability
+ * @dev: device to which the capability would be relevant, if available
+ * @cap: IOMMU capability
+ *
+ * Return: true if an IOMMU is present and supports the given capability
+ * for the given device, otherwise false.
+ */
+bool device_iommu_capable(struct device *dev, enum iommu_cap cap)
+{
+	const struct iommu_ops *ops;
+
+	if (!dev->iommu || !dev->iommu->iommu_dev)
+		return false;
+
+	ops = dev_iommu_ops(dev);
+	if (!ops->capable)
+		return false;
+
+	return ops->capable(dev, cap);
+}
+EXPORT_SYMBOL_GPL(device_iommu_capable);
+
 bool iommu_capable(struct bus_type *bus, enum iommu_cap cap)
 {
 	if (!bus->iommu_ops || !bus->iommu_ops->capable)
 		return false;
 
-	return bus->iommu_ops->capable(cap);
+	return bus->iommu_ops->capable(NULL, cap);
 }
 EXPORT_SYMBOL_GPL(iommu_capable);
 
diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c
index 5f5f4bd91e6f..ea4ba9de04af 100644
--- a/drivers/iommu/s390-iommu.c
+++ b/drivers/iommu/s390-iommu.c
@@ -39,7 +39,7 @@ static struct s390_domain *to_s390_domain(struct iommu_domain *dom)
 	return container_of(dom, struct s390_domain, domain);
 }
 
-static bool s390_iommu_capable(enum iommu_cap cap)
+static bool s390_iommu_capable(struct device *dev, enum iommu_cap cap)
 {
 	switch (cap) {
 	case IOMMU_CAP_CACHE_COHERENCY:
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 4a25f8241207..1fa927e6f1c6 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -219,7 +219,7 @@ struct iommu_iotlb_gather {
  * @owner: Driver module providing these ops
  */
 struct iommu_ops {
-	bool (*capable)(enum iommu_cap);
+	bool (*capable)(struct device *dev, enum iommu_cap);
 
 	/* Domain allocation and freeing by the iommu driver */
 	struct iommu_domain *(*domain_alloc)(unsigned iommu_domain_type);
@@ -415,6 +415,7 @@ static inline const struct iommu_ops *dev_iommu_ops(struct device *dev)
 #define IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER	6 /* Post Driver unbind */
 
 extern int bus_iommu_probe(struct bus_type *bus);
+extern bool device_iommu_capable(struct device *dev, enum iommu_cap cap);
 extern bool iommu_capable(struct bus_type *bus, enum iommu_cap cap);
 extern struct iommu_domain *iommu_domain_alloc(struct device *dev);
 extern struct iommu_group *iommu_group_get_by_id(int id);
@@ -682,6 +683,11 @@ struct iommu_device {};
 struct iommu_fault_param {};
 struct iommu_iotlb_gather {};
 
+static inline bool device_iommu_capable(struct device *dev, enum iommu_cap cap)
+{
+	return false;
+}
+
 static inline bool iommu_capable(struct bus_type *bus, enum iommu_cap cap)
 {
 	return false;
-- 
2.28.0.dirty


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 2/4] iommu: Add capability for pre-boot DMA protection
  2022-04-05 10:41 [PATCH v3 0/4] thunderbolt: Make iommu_dma_protection more accurate Robin Murphy
  2022-04-05 10:41 ` [PATCH v3 1/4] iommu: Introduce device_iommu_capable() Robin Murphy
@ 2022-04-05 10:41 ` Robin Murphy
  2022-04-06 10:28   ` Lu Baolu
  2022-04-05 10:41 ` [PATCH v3 3/4] thunderbolt: Make iommu_dma_protection more accurate Robin Murphy
  2022-04-05 10:41 ` [PATCH v3 4/4] iommu/amd: Indicate whether DMA remap support is enabled Robin Murphy
  3 siblings, 1 reply; 10+ messages in thread
From: Robin Murphy @ 2022-04-05 10:41 UTC (permalink / raw)
  To: joro, baolu.lu, andreas.noever, michael.jamet, mika.westerberg,
	YehezkelShB
  Cc: iommu, linux-usb, linux-kernel, mario.limonciello, hch

VT-d's dmar_platform_optin() actually represents a combination of
properties fairly well standardised by Microsoft as "Pre-boot DMA
Protection" and "Kernel DMA Protection"[1]. As such, we can provide
interested consumers with an abstracted capability rather than
driver-specific interfaces that won't scale. We name it for the former
aspect since that's what external callers are most likely to be
interested in; the latter is for the IOMMU layer to handle itself.

[1] https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-kernel-dma-protection

Suggested-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
 drivers/iommu/intel/iommu.c | 2 ++
 include/linux/iommu.h       | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 255304eb3b1f..49d552a96098 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4550,6 +4550,8 @@ static bool intel_iommu_capable(struct device *dev, enum iommu_cap cap)
 		return domain_update_iommu_snooping(NULL);
 	if (cap == IOMMU_CAP_INTR_REMAP)
 		return irq_remapping_enabled == 1;
+	if (cap == IOMMU_CAP_PRE_BOOT_PROTECTION)
+		return dmar_platform_optin();
 
 	return false;
 }
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 1fa927e6f1c6..64c02f472f7b 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -107,6 +107,8 @@ enum iommu_cap {
 					   transactions */
 	IOMMU_CAP_INTR_REMAP,		/* IOMMU supports interrupt isolation */
 	IOMMU_CAP_NOEXEC,		/* IOMMU_NOEXEC flag */
+	IOMMU_CAP_PRE_BOOT_PROTECTION,	/* Firmware says it used the IOMMU for
+					   DMA protection and we should too */
 };
 
 /* These are the possible reserved region types */
-- 
2.28.0.dirty


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 3/4] thunderbolt: Make iommu_dma_protection more accurate
  2022-04-05 10:41 [PATCH v3 0/4] thunderbolt: Make iommu_dma_protection more accurate Robin Murphy
  2022-04-05 10:41 ` [PATCH v3 1/4] iommu: Introduce device_iommu_capable() Robin Murphy
  2022-04-05 10:41 ` [PATCH v3 2/4] iommu: Add capability for pre-boot DMA protection Robin Murphy
@ 2022-04-05 10:41 ` Robin Murphy
  2022-04-05 12:09   ` Mika Westerberg
  2022-04-05 10:41 ` [PATCH v3 4/4] iommu/amd: Indicate whether DMA remap support is enabled Robin Murphy
  3 siblings, 1 reply; 10+ messages in thread
From: Robin Murphy @ 2022-04-05 10:41 UTC (permalink / raw)
  To: joro, baolu.lu, andreas.noever, michael.jamet, mika.westerberg,
	YehezkelShB
  Cc: iommu, linux-usb, linux-kernel, mario.limonciello, hch

Between me trying to get rid of iommu_present() and Mario wanting to
support the AMD equivalent of DMAR_PLATFORM_OPT_IN, scrutiny has shown
that the iommu_dma_protection attribute is being far too optimistic.
Even if an IOMMU might be present for some PCI segment in the system,
that doesn't necessarily mean it provides translation for the device(s)
we care about. Furthermore, all that DMAR_PLATFORM_OPT_IN really does
is tell us that memory was protected before the kernel was loaded, and
prevent the user from disabling the intel-iommu driver entirely. While
that lets us assume kernel integrity, what matters for actual runtime
DMA protection is whether we trust individual devices, based on the
"external facing" property that we expect firmware to describe for
Thunderbolt ports.

It's proven challenging to determine the appropriate ports accurately
given the variety of possible topologies, so while still not getting a
perfect answer, by putting enough faith in firmware we can at least get
a good bit closer. If we can see that any device near a Thunderbolt NHI
has all the requisites for Kernel DMA Protection, chances are that it
*is* a relevant port, but moreover that implies that firmware is playing
the game overall, so we'll use that to assume that all Thunderbolt ports
should be correctly marked and thus will end up fully protected.

CC: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---

v3: Check for correct external_facing property, add debug message.

 drivers/thunderbolt/domain.c | 12 +++-------
 drivers/thunderbolt/nhi.c    | 44 ++++++++++++++++++++++++++++++++++++
 include/linux/thunderbolt.h  |  2 ++
 3 files changed, 49 insertions(+), 9 deletions(-)

diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
index 7018d959f775..2889a214dadc 100644
--- a/drivers/thunderbolt/domain.c
+++ b/drivers/thunderbolt/domain.c
@@ -7,9 +7,7 @@
  */
 
 #include <linux/device.h>
-#include <linux/dmar.h>
 #include <linux/idr.h>
-#include <linux/iommu.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
@@ -257,13 +255,9 @@ static ssize_t iommu_dma_protection_show(struct device *dev,
 					 struct device_attribute *attr,
 					 char *buf)
 {
-	/*
-	 * Kernel DMA protection is a feature where Thunderbolt security is
-	 * handled natively using IOMMU. It is enabled when IOMMU is
-	 * enabled and ACPI DMAR table has DMAR_PLATFORM_OPT_IN set.
-	 */
-	return sprintf(buf, "%d\n",
-		       iommu_present(&pci_bus_type) && dmar_platform_optin());
+	struct tb *tb = container_of(dev, struct tb, dev);
+
+	return sysfs_emit(buf, "%d\n", tb->nhi->iommu_dma_protection);
 }
 static DEVICE_ATTR_RO(iommu_dma_protection);
 
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index 4a582183f675..4bc87b0f003a 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -15,9 +15,11 @@
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
+#include <linux/iommu.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/property.h>
+#include <linux/string_helpers.h>
 
 #include "nhi.h"
 #include "nhi_regs.h"
@@ -1103,6 +1105,47 @@ static void nhi_check_quirks(struct tb_nhi *nhi)
 		nhi->quirks |= QUIRK_AUTO_CLEAR_INT;
 }
 
+static int nhi_check_iommu_pdev(struct pci_dev *pdev, void *data)
+{
+	if (!pdev->external_facing ||
+	    !device_iommu_capable(&pdev->dev, IOMMU_CAP_PRE_BOOT_PROTECTION))
+		return 0;
+	*(bool *)data = true;
+	return 1; /* Stop walking */
+}
+
+static void nhi_check_iommu(struct tb_nhi *nhi)
+{
+	struct pci_bus *bus = nhi->pdev->bus;
+	bool port_ok = false;
+
+	/*
+	 * Ideally what we'd do here is grab every PCI device that
+	 * represents a tunnelling adapter for this NHI and check their
+	 * status directly, but unfortunately USB4 seems to make it
+	 * obnoxiously difficult to reliably make any correlation.
+	 *
+	 * So for now we'll have to bodge it... Hoping that the system
+	 * is at least sane enough that an adapter is in the same PCI
+	 * segment as its NHI, if we can find *something* on that segment
+	 * which meets the requirements for Kernel DMA Protection, we'll
+	 * take that to imply that firmware is aware and has (hopefully)
+	 * done the right thing in general. We need to know that the PCI
+	 * layer has seen the ExternalFacingPort property which will then
+	 * inform the IOMMU layer to enforce the complete "untrusted DMA"
+	 * flow, but also that the IOMMU driver itself can be trusted not
+	 * to have been subverted by a pre-boot DMA attack.
+	 */
+	while (bus->parent)
+		bus = bus->parent;
+
+	pci_walk_bus(bus, nhi_check_iommu_pdev, &port_ok);
+
+	nhi->iommu_dma_protection = port_ok;
+	dev_dbg(&nhi->pdev->dev, "IOMMU DMA protection is %s\n",
+		str_enabled_disabled(port_ok));
+}
+
 static int nhi_init_msi(struct tb_nhi *nhi)
 {
 	struct pci_dev *pdev = nhi->pdev;
@@ -1220,6 +1263,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		return -ENOMEM;
 
 	nhi_check_quirks(nhi);
+	nhi_check_iommu(nhi);
 
 	res = nhi_init_msi(nhi);
 	if (res) {
diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h
index 124e13cb1469..7a8ad984e651 100644
--- a/include/linux/thunderbolt.h
+++ b/include/linux/thunderbolt.h
@@ -465,6 +465,7 @@ static inline struct tb_xdomain *tb_service_parent(struct tb_service *svc)
  * @msix_ida: Used to allocate MSI-X vectors for rings
  * @going_away: The host controller device is about to disappear so when
  *		this flag is set, avoid touching the hardware anymore.
+ * @iommu_dma_protection: An IOMMU will isolate external-facing ports.
  * @interrupt_work: Work scheduled to handle ring interrupt when no
  *		    MSI-X is used.
  * @hop_count: Number of rings (end point hops) supported by NHI.
@@ -479,6 +480,7 @@ struct tb_nhi {
 	struct tb_ring **rx_rings;
 	struct ida msix_ida;
 	bool going_away;
+	bool iommu_dma_protection;
 	struct work_struct interrupt_work;
 	u32 hop_count;
 	unsigned long quirks;
-- 
2.28.0.dirty


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 4/4] iommu/amd: Indicate whether DMA remap support is enabled
  2022-04-05 10:41 [PATCH v3 0/4] thunderbolt: Make iommu_dma_protection more accurate Robin Murphy
                   ` (2 preceding siblings ...)
  2022-04-05 10:41 ` [PATCH v3 3/4] thunderbolt: Make iommu_dma_protection more accurate Robin Murphy
@ 2022-04-05 10:41 ` Robin Murphy
  2022-04-06  5:28   ` Christoph Hellwig
  3 siblings, 1 reply; 10+ messages in thread
From: Robin Murphy @ 2022-04-05 10:41 UTC (permalink / raw)
  To: joro, baolu.lu, andreas.noever, michael.jamet, mika.westerberg,
	YehezkelShB
  Cc: iommu, linux-usb, linux-kernel, mario.limonciello, hch

From: Mario Limonciello <mario.limonciello@amd.com>

Bit 1 of the IVFS IVInfo field indicates that IOMMU has been used for
pre-boot DMA protection.

Export this capability to allow other places in the kernel to be able to
check for it on AMD systems.

Link: https://www.amd.com/system/files/TechDocs/48882_IOMMU.pdf
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---

v4: Added to series from previous posting here:
https://lore.kernel.org/linux-iommu/20220318223104.7049-1-mario.limonciello@amd.com/

 drivers/iommu/amd/amd_iommu_types.h | 4 ++++
 drivers/iommu/amd/init.c            | 3 +++
 drivers/iommu/amd/iommu.c           | 2 ++
 3 files changed, 9 insertions(+)

diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
index 47108ed44fbb..72d0f5e2f651 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -407,6 +407,7 @@
 /* IOMMU IVINFO */
 #define IOMMU_IVINFO_OFFSET     36
 #define IOMMU_IVINFO_EFRSUP     BIT(0)
+#define IOMMU_IVINFO_DMA_REMAP  BIT(1)
 
 /* IOMMU Feature Reporting Field (for IVHD type 10h */
 #define IOMMU_FEAT_GASUP_SHIFT	6
@@ -449,6 +450,9 @@ extern struct irq_remap_table **irq_lookup_table;
 /* Interrupt remapping feature used? */
 extern bool amd_iommu_irq_remap;
 
+/* IVRS indicates that pre-boot remapping was enabled */
+extern bool amdr_ivrs_remap_support;
+
 /* kmem_cache to get tables with 128 byte alignement */
 extern struct kmem_cache *amd_iommu_irq_cache;
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index b4a798c7b347..0467918bf7fd 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -182,6 +182,7 @@ u32 amd_iommu_max_pasid __read_mostly = ~0;
 
 bool amd_iommu_v2_present __read_mostly;
 static bool amd_iommu_pc_present __read_mostly;
+bool amdr_ivrs_remap_support __read_mostly;
 
 bool amd_iommu_force_isolation __read_mostly;
 
@@ -326,6 +327,8 @@ static void __init early_iommu_features_init(struct amd_iommu *iommu,
 {
 	if (amd_iommu_ivinfo & IOMMU_IVINFO_EFRSUP)
 		iommu->features = h->efr_reg;
+	if (amd_iommu_ivinfo & IOMMU_IVINFO_DMA_REMAP)
+		amdr_ivrs_remap_support = true;
 }
 
 /* Access to l1 and l2 indexed register spaces */
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index e412a50dce59..81305c076de1 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2141,6 +2141,8 @@ static bool amd_iommu_capable(struct device *dev, enum iommu_cap cap)
 		return (irq_remapping_enabled == 1);
 	case IOMMU_CAP_NOEXEC:
 		return false;
+	case IOMMU_CAP_PRE_BOOT_PROTECTION:
+		return amdr_ivrs_remap_support;
 	default:
 		break;
 	}
-- 
2.28.0.dirty


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 3/4] thunderbolt: Make iommu_dma_protection more accurate
  2022-04-05 10:41 ` [PATCH v3 3/4] thunderbolt: Make iommu_dma_protection more accurate Robin Murphy
@ 2022-04-05 12:09   ` Mika Westerberg
  0 siblings, 0 replies; 10+ messages in thread
From: Mika Westerberg @ 2022-04-05 12:09 UTC (permalink / raw)
  To: Robin Murphy
  Cc: joro, baolu.lu, andreas.noever, michael.jamet, YehezkelShB,
	iommu, linux-usb, linux-kernel, mario.limonciello, hch

On Tue, Apr 05, 2022 at 11:41:03AM +0100, Robin Murphy wrote:
> Between me trying to get rid of iommu_present() and Mario wanting to
> support the AMD equivalent of DMAR_PLATFORM_OPT_IN, scrutiny has shown
> that the iommu_dma_protection attribute is being far too optimistic.
> Even if an IOMMU might be present for some PCI segment in the system,
> that doesn't necessarily mean it provides translation for the device(s)
> we care about. Furthermore, all that DMAR_PLATFORM_OPT_IN really does
> is tell us that memory was protected before the kernel was loaded, and
> prevent the user from disabling the intel-iommu driver entirely. While
> that lets us assume kernel integrity, what matters for actual runtime
> DMA protection is whether we trust individual devices, based on the
> "external facing" property that we expect firmware to describe for
> Thunderbolt ports.
> 
> It's proven challenging to determine the appropriate ports accurately
> given the variety of possible topologies, so while still not getting a
> perfect answer, by putting enough faith in firmware we can at least get
> a good bit closer. If we can see that any device near a Thunderbolt NHI
> has all the requisites for Kernel DMA Protection, chances are that it
> *is* a relevant port, but moreover that implies that firmware is playing
> the game overall, so we'll use that to assume that all Thunderbolt ports
> should be correctly marked and thus will end up fully protected.
> 
> CC: Mario Limonciello <mario.limonciello@amd.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>

Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 1/4] iommu: Introduce device_iommu_capable()
  2022-04-05 10:41 ` [PATCH v3 1/4] iommu: Introduce device_iommu_capable() Robin Murphy
@ 2022-04-06  5:28   ` Christoph Hellwig
  2022-04-06 10:32     ` Robin Murphy
  0 siblings, 1 reply; 10+ messages in thread
From: Christoph Hellwig @ 2022-04-06  5:28 UTC (permalink / raw)
  To: Robin Murphy
  Cc: joro, baolu.lu, andreas.noever, michael.jamet, mika.westerberg,
	YehezkelShB, iommu, linux-usb, linux-kernel, mario.limonciello,
	hch

On Tue, Apr 05, 2022 at 11:41:01AM +0100, Robin Murphy wrote:
> iommu_capable() only really works for systems where all IOMMU instances
> are completely homogeneous, and all devices are IOMMU-mapped. Implement
> the new variant which can give an accurate answer for whichever device
> the caller is actually interested in.
> 
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> ---
> 
> v3: New patch; now that the dev_iommu_ops() work has landed we can go
>     straight to a proper implementation. Also s/dev/device/ to match
>     the precedent of device_iommu_mapped() for the public API.

I'm a little worrited about a method with a parameter than can be
NULL.

Also usnic, vmd, and vdpa really want to use your new
device_iommu_capable as they check based on a device.  Just VFIO
is special as usual..

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 4/4] iommu/amd: Indicate whether DMA remap support is enabled
  2022-04-05 10:41 ` [PATCH v3 4/4] iommu/amd: Indicate whether DMA remap support is enabled Robin Murphy
@ 2022-04-06  5:28   ` Christoph Hellwig
  0 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2022-04-06  5:28 UTC (permalink / raw)
  To: Robin Murphy
  Cc: joro, baolu.lu, andreas.noever, michael.jamet, mika.westerberg,
	YehezkelShB, iommu, linux-usb, linux-kernel, mario.limonciello,
	hch

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 2/4] iommu: Add capability for pre-boot DMA protection
  2022-04-05 10:41 ` [PATCH v3 2/4] iommu: Add capability for pre-boot DMA protection Robin Murphy
@ 2022-04-06 10:28   ` Lu Baolu
  0 siblings, 0 replies; 10+ messages in thread
From: Lu Baolu @ 2022-04-06 10:28 UTC (permalink / raw)
  To: Robin Murphy, joro, andreas.noever, michael.jamet,
	mika.westerberg, YehezkelShB
  Cc: baolu.lu, iommu, linux-usb, linux-kernel, mario.limonciello, hch

On 2022/4/5 18:41, Robin Murphy wrote:
> VT-d's dmar_platform_optin() actually represents a combination of
> properties fairly well standardised by Microsoft as "Pre-boot DMA
> Protection" and "Kernel DMA Protection"[1]. As such, we can provide
> interested consumers with an abstracted capability rather than
> driver-specific interfaces that won't scale. We name it for the former
> aspect since that's what external callers are most likely to be
> interested in; the latter is for the IOMMU layer to handle itself.
> 
> [1] https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-kernel-dma-protection
> 
> Suggested-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>

Best regards,
baolu

> ---
>   drivers/iommu/intel/iommu.c | 2 ++
>   include/linux/iommu.h       | 2 ++
>   2 files changed, 4 insertions(+)
> 
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index 255304eb3b1f..49d552a96098 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4550,6 +4550,8 @@ static bool intel_iommu_capable(struct device *dev, enum iommu_cap cap)
>   		return domain_update_iommu_snooping(NULL);
>   	if (cap == IOMMU_CAP_INTR_REMAP)
>   		return irq_remapping_enabled == 1;
> +	if (cap == IOMMU_CAP_PRE_BOOT_PROTECTION)
> +		return dmar_platform_optin();
>   
>   	return false;
>   }
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 1fa927e6f1c6..64c02f472f7b 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -107,6 +107,8 @@ enum iommu_cap {
>   					   transactions */
>   	IOMMU_CAP_INTR_REMAP,		/* IOMMU supports interrupt isolation */
>   	IOMMU_CAP_NOEXEC,		/* IOMMU_NOEXEC flag */
> +	IOMMU_CAP_PRE_BOOT_PROTECTION,	/* Firmware says it used the IOMMU for
> +					   DMA protection and we should too */
>   };
>   
>   /* These are the possible reserved region types */

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 1/4] iommu: Introduce device_iommu_capable()
  2022-04-06  5:28   ` Christoph Hellwig
@ 2022-04-06 10:32     ` Robin Murphy
  0 siblings, 0 replies; 10+ messages in thread
From: Robin Murphy @ 2022-04-06 10:32 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: joro, baolu.lu, andreas.noever, michael.jamet, mika.westerberg,
	YehezkelShB, iommu, linux-usb, linux-kernel, mario.limonciello

On 2022-04-06 06:28, Christoph Hellwig wrote:
> On Tue, Apr 05, 2022 at 11:41:01AM +0100, Robin Murphy wrote:
>> iommu_capable() only really works for systems where all IOMMU instances
>> are completely homogeneous, and all devices are IOMMU-mapped. Implement
>> the new variant which can give an accurate answer for whichever device
>> the caller is actually interested in.
>>
>> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
>> ---
>>
>> v3: New patch; now that the dev_iommu_ops() work has landed we can go
>>      straight to a proper implementation. Also s/dev/device/ to match
>>      the precedent of device_iommu_mapped() for the public API.
> 
> I'm a little worrited about a method with a parameter than can be
> NULL.

FWIW, the intent is that that's only temporary.

> Also usnic, vmd, and vdpa really want to use your new
> device_iommu_capable as they check based on a device.  Just VFIO
> is special as usual..

Indeed, I have those patches in my stack already, I'm just waiting for 
this to land before I think about posting them. Once the DMA ownership 
series lands in parallel, VFIO can also get converted and 
iommu_capable() goes away entirely. At that point I have a patch for the 
Arm SMMU drivers to start actually using the new device argument, but 
Jason's new proposal now puts a twist on that...

On reflection, there's no real need for the internal method to change in 
lock-step with the external interface. I've no objection to holding off 
on adding that new parameter until it's reliably useful, and indeed now 
that I'm looking at it outside the context of the entire cleanup 
mission, that does sound like the right thing to do anyway :)

(also it turns out I need to respin this patch regardless since I 
generated it from the wrong point in my branch, where iommu_present() 
was already gone from the context in iommu.h...)

Cheers,
Robin.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2022-04-06 14:21 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-05 10:41 [PATCH v3 0/4] thunderbolt: Make iommu_dma_protection more accurate Robin Murphy
2022-04-05 10:41 ` [PATCH v3 1/4] iommu: Introduce device_iommu_capable() Robin Murphy
2022-04-06  5:28   ` Christoph Hellwig
2022-04-06 10:32     ` Robin Murphy
2022-04-05 10:41 ` [PATCH v3 2/4] iommu: Add capability for pre-boot DMA protection Robin Murphy
2022-04-06 10:28   ` Lu Baolu
2022-04-05 10:41 ` [PATCH v3 3/4] thunderbolt: Make iommu_dma_protection more accurate Robin Murphy
2022-04-05 12:09   ` Mika Westerberg
2022-04-05 10:41 ` [PATCH v3 4/4] iommu/amd: Indicate whether DMA remap support is enabled Robin Murphy
2022-04-06  5:28   ` Christoph Hellwig

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).