xref: /kvm-unit-tests/x86/intel-iommu.c (revision 92d2c192ff927d9c121fa8006000ebcb1f9ad2d5)
1 /*
2  * Intel IOMMU unit test.
3  *
4  * Copyright (C) 2016 Red Hat, Inc.
5  *
6  * Authors:
7  *   Peter Xu <peterx@redhat.com>,
8  *
9  * This work is licensed under the terms of the GNU LGPL, version 2 or
10  * later.
11  */
12 
13 #include "intel-iommu.h"
14 #include "pci-edu.h"
15 
16 #define VTD_TEST_DMAR_4B ("DMAR 4B memcpy test")
17 
18 void vtd_test_dmar(struct pci_edu_dev *dev)
19 {
20 	void *page = alloc_page();
21 
22 #define DMA_TEST_WORD (0x12345678)
23 	/* Modify the first 4 bytes of the page */
24 	*(uint32_t *)page = DMA_TEST_WORD;
25 
26 	/*
27 	 * Map the newly allocated page into IOVA address 0 (size 4K)
28 	 * of the device address space. Root entry and context entry
29 	 * will be automatically created when needed.
30 	 */
31 	vtd_map_range(dev->pci_dev.bdf, 0, virt_to_phys(page), PAGE_SIZE);
32 
33 	/*
34 	 * DMA the first 4 bytes of the page to EDU device buffer
35 	 * offset 0.
36 	 */
37 	edu_dma(dev, 0, 4, 0, false);
38 
39 	/*
40 	 * DMA the first 4 bytes of EDU device buffer into the page
41 	 * with offset 4 (so it'll be using 4-7 bytes).
42 	 */
43 	edu_dma(dev, 4, 4, 0, true);
44 
45 	/*
46 	 * Check data match between 0-3 bytes and 4-7 bytes of the
47 	 * page.
48 	 */
49 	report(VTD_TEST_DMAR_4B, *((uint32_t *)page + 1) == DMA_TEST_WORD);
50 
51 	free_page(page);
52 }
53 
54 int main(int argc, char *argv[])
55 {
56 	struct pci_edu_dev dev;
57 
58 	vtd_init();
59 
60 	report("fault status check", vtd_readl(DMAR_FSTS_REG) == 0);
61 	report("QI enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_QI);
62 	report("DMAR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_ROOT);
63 	report("IR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE);
64 	report("DMAR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR);
65 	report("IR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR);
66 	report("DMAR support 39 bits address width",
67 	       vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW);
68 	report("DMAR support huge pages", vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS);
69 
70 	if (!edu_init(&dev)) {
71 		printf("Please specify \"-device edu\" to do "
72 		       "further IOMMU tests.\n");
73 		report_skip(VTD_TEST_DMAR_4B);
74 	} else
75 		vtd_test_dmar(&dev);
76 
77 	return report_summary();
78 }
79