Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

vfio: selftests: Validate 2M/1G HugeTLB are mapped as 2M/1G in IOMMU

Update vfio dma mapping test to verify that the IOMMU uses 2M and 1G
mappings when 2M and 1G HugeTLB pages are mapped into a device
respectively.

This validation is done by inspecting the contents of the I/O page
tables via /sys/kernel/debug/iommu/intel/. This validation is skipped if
that directory is not available (i.e. non-Intel IOMMUs).

Signed-off-by: Josh Hilke <jrhilke@google.com>
[reword commit message, refactor code]
Acked-by: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: David Matlack <dmatlack@google.com>
Link: https://lore.kernel.org/r/20250822212518.4156428-9-dmatlack@google.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

authored by

Josh Hilke and committed by
Alex Williamson
47f86104 751f6b5d

+111
+111
tools/testing/selftests/vfio/vfio_dma_mapping_test.c
··· 14 14 15 15 static const char *device_bdf; 16 16 17 + struct iommu_mapping { 18 + u64 pgd; 19 + u64 p4d; 20 + u64 pud; 21 + u64 pmd; 22 + u64 pte; 23 + }; 24 + 25 + static void parse_next_value(char **line, u64 *value) 26 + { 27 + char *token; 28 + 29 + token = strtok_r(*line, " \t|\n", line); 30 + if (!token) 31 + return; 32 + 33 + /* Caller verifies `value`. No need to check return value. */ 34 + sscanf(token, "0x%lx", value); 35 + } 36 + 37 + static int intel_iommu_mapping_get(const char *bdf, u64 iova, 38 + struct iommu_mapping *mapping) 39 + { 40 + char iommu_mapping_path[PATH_MAX], line[PATH_MAX]; 41 + u64 line_iova = -1; 42 + int ret = -ENOENT; 43 + FILE *file; 44 + char *rest; 45 + 46 + snprintf(iommu_mapping_path, sizeof(iommu_mapping_path), 47 + "/sys/kernel/debug/iommu/intel/%s/domain_translation_struct", 48 + bdf); 49 + 50 + printf("Searching for IOVA 0x%lx in %s\n", iova, iommu_mapping_path); 51 + 52 + file = fopen(iommu_mapping_path, "r"); 53 + VFIO_ASSERT_NOT_NULL(file, "fopen(%s) failed", iommu_mapping_path); 54 + 55 + while (fgets(line, sizeof(line), file)) { 56 + rest = line; 57 + 58 + parse_next_value(&rest, &line_iova); 59 + if (line_iova != (iova / getpagesize())) 60 + continue; 61 + 62 + /* 63 + * Ensure each struct field is initialized in case of empty 64 + * page table values. 65 + */ 66 + memset(mapping, 0, sizeof(*mapping)); 67 + parse_next_value(&rest, &mapping->pgd); 68 + parse_next_value(&rest, &mapping->p4d); 69 + parse_next_value(&rest, &mapping->pud); 70 + parse_next_value(&rest, &mapping->pmd); 71 + parse_next_value(&rest, &mapping->pte); 72 + 73 + ret = 0; 74 + break; 75 + } 76 + 77 + fclose(file); 78 + 79 + if (ret) 80 + printf("IOVA not found\n"); 81 + 82 + return ret; 83 + } 84 + 85 + static int iommu_mapping_get(const char *bdf, u64 iova, 86 + struct iommu_mapping *mapping) 87 + { 88 + if (!access("/sys/kernel/debug/iommu/intel", F_OK)) 89 + return intel_iommu_mapping_get(bdf, iova, mapping); 90 + 91 + return -EOPNOTSUPP; 92 + } 93 + 17 94 FIXTURE(vfio_dma_mapping_test) { 18 95 struct vfio_pci_device *device; 19 96 }; ··· 128 51 { 129 52 const u64 size = variant->size ?: getpagesize(); 130 53 const int flags = variant->mmap_flags; 54 + struct iommu_mapping mapping; 131 55 void *mem; 132 56 u64 iova; 57 + int rc; 133 58 134 59 mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); 135 60 ··· 146 67 vfio_pci_dma_map(self->device, iova, size, mem); 147 68 printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", mem, size, iova); 148 69 70 + rc = iommu_mapping_get(device_bdf, iova, &mapping); 71 + if (rc == -EOPNOTSUPP) 72 + goto unmap; 73 + 74 + ASSERT_EQ(0, rc); 75 + printf("Found IOMMU mappings for IOVA 0x%lx:\n", iova); 76 + printf("PGD: 0x%016lx\n", mapping.pgd); 77 + printf("P4D: 0x%016lx\n", mapping.p4d); 78 + printf("PUD: 0x%016lx\n", mapping.pud); 79 + printf("PMD: 0x%016lx\n", mapping.pmd); 80 + printf("PTE: 0x%016lx\n", mapping.pte); 81 + 82 + switch (size) { 83 + case SZ_4K: 84 + ASSERT_NE(0, mapping.pte); 85 + break; 86 + case SZ_2M: 87 + ASSERT_EQ(0, mapping.pte); 88 + ASSERT_NE(0, mapping.pmd); 89 + break; 90 + case SZ_1G: 91 + ASSERT_EQ(0, mapping.pte); 92 + ASSERT_EQ(0, mapping.pmd); 93 + ASSERT_NE(0, mapping.pud); 94 + break; 95 + default: 96 + VFIO_FAIL("Unrecognized size: 0x%lx\n", size); 97 + } 98 + 99 + unmap: 149 100 vfio_pci_dma_unmap(self->device, iova, size); 101 + printf("Unmapped IOVA 0x%lx\n", iova); 102 + ASSERT_NE(0, iommu_mapping_get(device_bdf, iova, &mapping)); 150 103 151 104 ASSERT_TRUE(!munmap(mem, size)); 152 105 }