]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommu/vt-d: Fix checks and print in pgtable_walk()
authorZhenzhong Duan <zhenzhong.duan@intel.com>
Mon, 4 Nov 2024 01:40:33 +0000 (09:40 +0800)
committerJoerg Roedel <jroedel@suse.de>
Tue, 5 Nov 2024 12:32:23 +0000 (13:32 +0100)
There are some issues in pgtable_walk():

1. Super page is dumped as non-present page
2. dma_pte_superpage() should not check against leaf page table entries
3. Pointer pte is never NULL so checking it is meaningless
4. When an entry is not present, it still makes sense to dump the entry
   content.

Fix 1,2 by checking dma_pte_superpage()'s returned value after level check.
Fix 3 by removing pte check.
Fix 4 by checking present bit after printing.

By this chance, change to print "page table not present" instead of "PTE
not present" to be clearer.

Fixes: 914ff7719e8a ("iommu/vt-d: Dump DMAR translation structure when DMA fault occurs")
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Link: https://lore.kernel.org/r/20241024092146.715063-3-zhenzhong.duan@intel.com
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/intel/iommu.c

index 2337baa3cb806da3271c8095c57e90ca2697647d..5095147f6ba259c033c3f0b5b41b4ebc05ba26dd 100644 (file)
@@ -596,14 +596,15 @@ static void pgtable_walk(struct intel_iommu *iommu, unsigned long pfn,
        while (1) {
                offset = pfn_level_offset(pfn, level);
                pte = &parent[offset];
-               if (!pte || (dma_pte_superpage(pte) || !dma_pte_present(pte))) {
-                       pr_info("PTE not present at level %d\n", level);
-                       break;
-               }
 
                pr_info("pte level: %d, pte value: 0x%016llx\n", level, pte->val);
 
-               if (level == 1)
+               if (!dma_pte_present(pte)) {
+                       pr_info("page table not present at level %d\n", level - 1);
+                       break;
+               }
+
+               if (level == 1 || dma_pte_superpage(pte))
                        break;
 
                parent = phys_to_virt(dma_pte_addr(pte));