[kvm-unit-tests PATCH] x86/intel-iommu: add test for address width 48 and 57.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Current iommu test only covers 39-bit address width. This patch
extends the test case to based on the supported maximum guest
address width.

Signed-off-by: Yu Zhang <yu.c.zhang@xxxxxxxxxxxxxxx>
---
 lib/x86/intel-iommu.c | 14 ++++----------
 lib/x86/intel-iommu.h | 11 ++++++++++-
 x86/intel-iommu.c     | 21 ++++++++++++++++-----
 3 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/lib/x86/intel-iommu.c b/lib/x86/intel-iommu.c
index 3f3f211..e1ea9d2 100644
--- a/lib/x86/intel-iommu.c
+++ b/lib/x86/intel-iommu.c
@@ -16,13 +16,6 @@
 #include "atomic.h"
 #include "alloc_page.h"
 
-/*
- * VT-d in QEMU currently only support 39 bits address width, which is
- * 3-level translation.
- */
-#define VTD_PAGE_LEVEL      3
-#define VTD_CE_AW_39BIT     0x1
-
 typedef uint64_t vtd_pte_t;
 
 struct vtd_root_entry {
@@ -75,6 +68,8 @@ typedef struct vtd_irte vtd_irte_t;
 #define VTD_IRTA_MASK (PAGE_MASK)
 
 void *vtd_reg_base;
+uint8_t max_gaw;
+uint8_t max_page_level;
 
 static uint64_t vtd_root_table(void)
 {
@@ -149,7 +144,7 @@ static void vtd_install_pte(vtd_pte_t *root, iova_t iova,
 	unsigned int offset;
 	void *page;
 
-	for (level = VTD_PAGE_LEVEL; level > level_target; level--) {
+	for (level = max_page_level; level > level_target; level--) {
 		offset = PGDIR_OFFSET(iova, level);
 		if (!(root[offset] & VTD_PTE_RW)) {
 			page = alloc_page();
@@ -213,8 +208,7 @@ void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
 		memset(ce, 0, sizeof(*ce));
 		/* To make it simple, domain ID is the same as SID */
 		ce->domain_id = sid;
-		/* We only test 39 bits width case (3-level paging) */
-		ce->addr_width = VTD_CE_AW_39BIT;
+		ce->addr_width = max_page_level - 2;
 		ce->slptptr = virt_to_phys(slptptr) >> VTD_PAGE_SHIFT;
 		ce->trans_type = VTD_CONTEXT_TT_MULTI_LEVEL;
 		ce->present = 1;
diff --git a/lib/x86/intel-iommu.h b/lib/x86/intel-iommu.h
index 05b9744..7057417 100644
--- a/lib/x86/intel-iommu.h
+++ b/lib/x86/intel-iommu.h
@@ -26,6 +26,7 @@
 #define Q35_HOST_BRIDGE_IOMMU_ADDR  0xfed90000ULL
 #define VTD_PAGE_SHIFT              PAGE_SHIFT
 #define VTD_PAGE_SIZE               PAGE_SIZE
+#define VTD_PAGE_LEVEL_STRIDE       9
 
 /*
  * Intel IOMMU register specification
@@ -100,7 +101,13 @@
 #define VTD_CAP_SAGAW_39bit         (0x2ULL << VTD_CAP_SAGAW_SHIFT)
 /* 48-bit AGAW, 4-level page-table */
 #define VTD_CAP_SAGAW_48bit         (0x4ULL << VTD_CAP_SAGAW_SHIFT)
-#define VTD_CAP_SAGAW               VTD_CAP_SAGAW_39bit
+/* 57-bit AGAW, 5-level page-table */
+#define VTD_CAP_SAGAW_57bit         (0x8ULL << VTD_CAP_SAGAW_SHIFT)
+#define VTD_CAP_SAGAW(cap)          (((cap) >> VTD_CAP_SAGAW_SHIFT) & 0x1fULL)
+
+/* Maximum Guest Address Widths */
+#define VTD_CAP_MGAW_SHIFT    16
+#define VTD_CAP_MGAW(cap)     ((((cap) >> VTD_CAP_MGAW_SHIFT) & 0x3fULL) + 1)
 
 /* Both 1G/2M huge pages */
 #define VTD_CAP_SLLPS               ((1ULL << 34) | (1ULL << 35))
@@ -118,6 +125,8 @@
 extern void *vtd_reg_base;
 #define vtd_reg(reg) ({ assert(vtd_reg_base); \
 			(volatile void *)(vtd_reg_base + reg); })
+extern  uint8_t max_gaw;
+extern  uint8_t max_page_level;
 
 static inline void vtd_writel(unsigned int reg, uint32_t value)
 {
diff --git a/x86/intel-iommu.c b/x86/intel-iommu.c
index f24170d..9d2194d 100644
--- a/x86/intel-iommu.c
+++ b/x86/intel-iommu.c
@@ -132,25 +132,36 @@ static void vtd_test_ir(void)
 
 int main(int argc, char *argv[])
 {
+	uint64_t dmar_cap;
+	uint8_t sagaw;
+
 	setup_vm();
 	smp_init();
-
 	vtd_init();
 
 	report_prefix_push("vtd_init");
-
 	report("fault status check", vtd_readl(DMAR_FSTS_REG) == 0);
 	report("QI enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_QI);
 	report("DMAR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_ROOT);
 	report("IR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE);
 	report("DMAR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR);
 	report("IR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR);
-	report("DMAR support 39 bits address width",
-	       vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW);
 	report("DMAR support huge pages", vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS);
-
 	report_prefix_pop();
 
+	dmar_cap = vtd_readq(DMAR_CAP_REG);
+	max_gaw = VTD_CAP_MGAW(dmar_cap);
+	sagaw = VTD_CAP_SAGAW(dmar_cap);
+	max_page_level = (max_gaw - VTD_PAGE_SHIFT)/VTD_PAGE_LEVEL_STRIDE;
+
+	report("address width check", ((1 << (max_page_level - 2)) & sagaw));
+	if (dmar_cap & VTD_CAP_SAGAW_39bit)
+		printf("DMAR supports 39 bits address width.\n");
+	if (dmar_cap & VTD_CAP_SAGAW_48bit)
+		printf("DMAR supports 48 bits address width.\n");
+	if (dmar_cap & VTD_CAP_SAGAW_57bit)
+		printf("DMAR supports 57 bits address width.\n");
+
 	if (!edu_init(&edu_dev)) {
 		printf("Please specify \"-device edu\" to do "
 		       "further IOMMU tests.\n");
-- 
1.9.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux