mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
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>
This commit is contained in:
parent
751f6b5d06
commit
47f861048e
|
|
@ -14,6 +14,83 @@
|
|||
|
||||
static const char *device_bdf;
|
||||
|
||||
struct iommu_mapping {
|
||||
u64 pgd;
|
||||
u64 p4d;
|
||||
u64 pud;
|
||||
u64 pmd;
|
||||
u64 pte;
|
||||
};
|
||||
|
||||
static void parse_next_value(char **line, u64 *value)
|
||||
{
|
||||
char *token;
|
||||
|
||||
token = strtok_r(*line, " \t|\n", line);
|
||||
if (!token)
|
||||
return;
|
||||
|
||||
/* Caller verifies `value`. No need to check return value. */
|
||||
sscanf(token, "0x%lx", value);
|
||||
}
|
||||
|
||||
static int intel_iommu_mapping_get(const char *bdf, u64 iova,
|
||||
struct iommu_mapping *mapping)
|
||||
{
|
||||
char iommu_mapping_path[PATH_MAX], line[PATH_MAX];
|
||||
u64 line_iova = -1;
|
||||
int ret = -ENOENT;
|
||||
FILE *file;
|
||||
char *rest;
|
||||
|
||||
snprintf(iommu_mapping_path, sizeof(iommu_mapping_path),
|
||||
"/sys/kernel/debug/iommu/intel/%s/domain_translation_struct",
|
||||
bdf);
|
||||
|
||||
printf("Searching for IOVA 0x%lx in %s\n", iova, iommu_mapping_path);
|
||||
|
||||
file = fopen(iommu_mapping_path, "r");
|
||||
VFIO_ASSERT_NOT_NULL(file, "fopen(%s) failed", iommu_mapping_path);
|
||||
|
||||
while (fgets(line, sizeof(line), file)) {
|
||||
rest = line;
|
||||
|
||||
parse_next_value(&rest, &line_iova);
|
||||
if (line_iova != (iova / getpagesize()))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ensure each struct field is initialized in case of empty
|
||||
* page table values.
|
||||
*/
|
||||
memset(mapping, 0, sizeof(*mapping));
|
||||
parse_next_value(&rest, &mapping->pgd);
|
||||
parse_next_value(&rest, &mapping->p4d);
|
||||
parse_next_value(&rest, &mapping->pud);
|
||||
parse_next_value(&rest, &mapping->pmd);
|
||||
parse_next_value(&rest, &mapping->pte);
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
if (ret)
|
||||
printf("IOVA not found\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iommu_mapping_get(const char *bdf, u64 iova,
|
||||
struct iommu_mapping *mapping)
|
||||
{
|
||||
if (!access("/sys/kernel/debug/iommu/intel", F_OK))
|
||||
return intel_iommu_mapping_get(bdf, iova, mapping);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
FIXTURE(vfio_dma_mapping_test) {
|
||||
struct vfio_pci_device *device;
|
||||
};
|
||||
|
|
@ -51,8 +128,10 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap)
|
|||
{
|
||||
const u64 size = variant->size ?: getpagesize();
|
||||
const int flags = variant->mmap_flags;
|
||||
struct iommu_mapping mapping;
|
||||
void *mem;
|
||||
u64 iova;
|
||||
int rc;
|
||||
|
||||
mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
|
||||
|
||||
|
|
@ -67,7 +146,39 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap)
|
|||
vfio_pci_dma_map(self->device, iova, size, mem);
|
||||
printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", mem, size, iova);
|
||||
|
||||
rc = iommu_mapping_get(device_bdf, iova, &mapping);
|
||||
if (rc == -EOPNOTSUPP)
|
||||
goto unmap;
|
||||
|
||||
ASSERT_EQ(0, rc);
|
||||
printf("Found IOMMU mappings for IOVA 0x%lx:\n", iova);
|
||||
printf("PGD: 0x%016lx\n", mapping.pgd);
|
||||
printf("P4D: 0x%016lx\n", mapping.p4d);
|
||||
printf("PUD: 0x%016lx\n", mapping.pud);
|
||||
printf("PMD: 0x%016lx\n", mapping.pmd);
|
||||
printf("PTE: 0x%016lx\n", mapping.pte);
|
||||
|
||||
switch (size) {
|
||||
case SZ_4K:
|
||||
ASSERT_NE(0, mapping.pte);
|
||||
break;
|
||||
case SZ_2M:
|
||||
ASSERT_EQ(0, mapping.pte);
|
||||
ASSERT_NE(0, mapping.pmd);
|
||||
break;
|
||||
case SZ_1G:
|
||||
ASSERT_EQ(0, mapping.pte);
|
||||
ASSERT_EQ(0, mapping.pmd);
|
||||
ASSERT_NE(0, mapping.pud);
|
||||
break;
|
||||
default:
|
||||
VFIO_FAIL("Unrecognized size: 0x%lx\n", size);
|
||||
}
|
||||
|
||||
unmap:
|
||||
vfio_pci_dma_unmap(self->device, iova, size);
|
||||
printf("Unmapped IOVA 0x%lx\n", iova);
|
||||
ASSERT_NE(0, iommu_mapping_get(device_bdf, iova, &mapping));
|
||||
|
||||
ASSERT_TRUE(!munmap(mem, size));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user