On Fri, Nov 09, 2018 at 08:02:40PM +0800, Yu Zhang wrote: > 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> Reviewed-by: Michael S. Tsirkin <mst@xxxxxxxxxx> > --- > 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