From cef74409ea79b0a37af6889e7abf7a2a9c47979b Mon Sep 17 00:00:00 2001 From: Gil Kupfer Date: Thu, 10 May 2018 17:56:02 -0500 Subject: [PATCH] PCI: Add "pci=noats" boot parameter Adds a "pci=noats" boot parameter. When supplied, all ATS related functions fail immediately and the IOMMU is configured to not use device-IOTLB. Any function that checks for ATS capabilities directly against the devices should also check this flag. Currently, such functions exist only in IOMMU drivers, and they are covered by this patch. The motivation behind this patch is the existence of malicious devices. Lots of research has been done about how to use the IOMMU as protection from such devices. When ATS is supported, any I/O device can access any physical address by faking device-IOTLB entries. Adding the ability to ignore these entries lets sysadmins enhance system security. Signed-off-by: Gil Kupfer Signed-off-by: Bjorn Helgaas Acked-by: Joerg Roedel --- Documentation/admin-guide/kernel-parameters.txt | 2 ++ drivers/iommu/amd_iommu.c | 11 ++++++++--- drivers/iommu/intel-iommu.c | 3 ++- drivers/pci/ats.c | 3 +++ drivers/pci/pci.c | 11 +++++++++++ include/linux/pci.h | 2 ++ 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 11fc28ecdb6d..a19ccac3b4c7 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3147,6 +3147,8 @@ on: Turn realloc on realloc same as realloc=on noari do not use PCIe ARI. + noats [PCIE, Intel-IOMMU, AMD-IOMMU] + do not use PCIe ATS (and IOMMU device IOTLB). pcie_scan_all Scan all possible PCIe devices. Otherwise we only look for one device below a PCIe downstream port. diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 2a99f0f14795..56da1c6121d3 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -355,6 +355,9 @@ static bool pci_iommuv2_capable(struct pci_dev *pdev) }; int i, pos; + if (pci_ats_disabled()) + return false; + for (i = 0; i < 3; ++i) { pos = pci_find_ext_capability(pdev, caps[i]); if (pos == 0) @@ -3524,9 +3527,11 @@ int amd_iommu_device_info(struct pci_dev *pdev, memset(info, 0, sizeof(*info)); - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ATS); - if (pos) - info->flags |= AMD_IOMMU_DEVICE_FLAG_ATS_SUP; + if (!pci_ats_disabled()) { + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ATS); + if (pos) + info->flags |= AMD_IOMMU_DEVICE_FLAG_ATS_SUP; + } pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); if (pos) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 749d8f235346..772b404a6604 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2459,7 +2459,8 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, if (dev && dev_is_pci(dev)) { struct pci_dev *pdev = to_pci_dev(info->dev); - if (ecap_dev_iotlb_support(iommu->ecap) && + if (!pci_ats_disabled() && + ecap_dev_iotlb_support(iommu->ecap) && pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ATS) && dmar_find_matched_atsr_unit(pdev)) info->ats_supported = 1; diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index 89305b569d3d..4923a2a8e14b 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -20,6 +20,9 @@ void pci_ats_init(struct pci_dev *dev) { int pos; + if (pci_ats_disabled()) + return; + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); if (!pos) return; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e597655a5643..789ce36be341 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -112,6 +112,14 @@ unsigned int pcibios_max_latency = 255; /* If set, the PCIe ARI capability will not be used. */ static bool pcie_ari_disabled; +/* If set, the PCIe ATS capability will not be used. */ +static bool pcie_ats_disabled; + +bool pci_ats_disabled(void) +{ + return pcie_ats_disabled; +} + /* Disable bridge_d3 for all PCIe ports */ static bool pci_bridge_d3_disable; /* Force bridge_d3 for all PCIe ports */ @@ -5793,6 +5801,9 @@ static int __init pci_setup(char *str) if (*str && (str = pcibios_setup(str)) && *str) { if (!strcmp(str, "nomsi")) { pci_no_msi(); + } else if (!strncmp(str, "noats", 5)) { + pr_info("PCIe: ATS is disabled\n"); + pcie_ats_disabled = true; } else if (!strcmp(str, "noaer")) { pci_no_aer(); } else if (!strncmp(str, "realloc=", 8)) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 911f9098a466..aa9c27e129d4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1479,6 +1479,8 @@ static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { } static inline void pcie_ecrc_get_policy(char *str) { } #endif +bool pci_ats_disabled(void); + #ifdef CONFIG_PCI_ATS /* Address Translation Service */ void pci_ats_init(struct pci_dev *dev); -- 2.11.0