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