aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBaoquan He <bhe@redhat.com>2017-08-09 04:33:42 -0400
committerJoerg Roedel <jroedel@suse.de>2017-08-15 12:14:40 -0400
commitb336781b82cc12c7940a2b1c806fbe7f78ecd72a (patch)
treeaf88008707223a08b2f7a44d43d5c8aa11baa00a
parentdf3f7a6e8e855e4ff533508807cd7c3723faa51f (diff)
iommu/amd: Allocate memory below 4G for dev table if translation pre-enabled
AMD pointed out it's unsafe to update the device-table while iommu is enabled. It turns out that device-table pointer update is split up into two 32bit writes in the IOMMU hardware. So updating it while the IOMMU is enabled could have some nasty side effects. The safe way to work around this is to always allocate the device-table below 4G, including the old device-table in normal kernel and the device-table used for copying the content of the old device-table in kdump kernel. Meanwhile we need check if the address of old device-table is above 4G because it might has been touched accidentally in corrupted 1st kernel. Signed-off-by: Baoquan He <bhe@redhat.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/amd_iommu_init.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index d08ad74b0928..c348732f27d7 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -885,11 +885,15 @@ static bool copy_device_table(void)
885 } 885 }
886 886
887 old_devtb_phys = entry & PAGE_MASK; 887 old_devtb_phys = entry & PAGE_MASK;
888 if (old_devtb_phys >= 0x100000000ULL) {
889 pr_err("The address of old device table is above 4G, not trustworthy!/n");
890 return false;
891 }
888 old_devtb = memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB); 892 old_devtb = memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB);
889 if (!old_devtb) 893 if (!old_devtb)
890 return false; 894 return false;
891 895
892 gfp_flag = GFP_KERNEL | __GFP_ZERO; 896 gfp_flag = GFP_KERNEL | __GFP_ZERO | GFP_DMA32;
893 old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag, 897 old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag,
894 get_order(dev_table_size)); 898 get_order(dev_table_size));
895 if (old_dev_tbl_cpy == NULL) { 899 if (old_dev_tbl_cpy == NULL) {
@@ -2432,7 +2436,8 @@ static int __init early_amd_iommu_init(void)
2432 2436
2433 /* Device table - directly used by all IOMMUs */ 2437 /* Device table - directly used by all IOMMUs */
2434 ret = -ENOMEM; 2438 ret = -ENOMEM;
2435 amd_iommu_dev_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 2439 amd_iommu_dev_table = (void *)__get_free_pages(
2440 GFP_KERNEL | __GFP_ZERO | GFP_DMA32,
2436 get_order(dev_table_size)); 2441 get_order(dev_table_size));
2437 if (amd_iommu_dev_table == NULL) 2442 if (amd_iommu_dev_table == NULL)
2438 goto out; 2443 goto out;