debuggers.hg

changeset 21073:c9f795ff78b1

VT-d: various initialization fixes

Detect invalid/unsupported configurations in iommu_alloc() - offsets
read from hardware must not lead to exceeding a single page (since
only that much gets mapped). This covers the apparently not uncommon
case of the address pointed to by a DMAR reading as all ones (Linux
for example also checks for this).

Further correct error handling of that function: Without storing the
allocated "struct iommu" instance in the drhd, iommu_free() won't do
anything, and hence all successfully set up pieces would be leaked.

Also keep iommu_free() from calling destroy_irq() when no irq was
ever set up.

Additionally, clear_fault_bits() has no need to read the capabilities
field from I/O memory - it's already cached in "struct iommu".

Finally, simplify print_iommu_regs() and its output, and actually use
this function.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Mar 11 17:15:54 2010 +0000 (2010-03-11)
parents 099aac2cfab6
children 4152a3ce90a7
files xen/drivers/passthrough/vtd/iommu.c xen/drivers/passthrough/vtd/utils.c
line diff
     1.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Thu Mar 11 17:15:27 2010 +0000
     1.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Thu Mar 11 17:15:54 2010 +0000
     1.3 @@ -1068,9 +1068,21 @@ static int iommu_alloc(struct acpi_drhd_
     1.4      iommu->cap = dmar_readq(iommu->reg, DMAR_CAP_REG);
     1.5      iommu->ecap = dmar_readq(iommu->reg, DMAR_ECAP_REG);
     1.6  
     1.7 -    dprintk(XENLOG_INFO VTDPREFIX,
     1.8 -             "drhd->address = %"PRIx64"\n", drhd->address);
     1.9 -    dprintk(XENLOG_INFO VTDPREFIX, "iommu->reg = %p\n", iommu->reg);
    1.10 +    drhd->iommu = iommu;
    1.11 +
    1.12 +    dprintk(XENLOG_DEBUG VTDPREFIX,
    1.13 +            "drhd->address = %"PRIx64" iommu->reg = %p\n",
    1.14 +            drhd->address, iommu->reg);
    1.15 +    dprintk(XENLOG_DEBUG VTDPREFIX,
    1.16 +            "cap = %"PRIx64" ecap = %"PRIx64"\n", iommu->cap, iommu->ecap);
    1.17 +    if ( cap_fault_reg_offset(iommu->cap) +
    1.18 +         cap_num_fault_regs(iommu->cap) * PRIMARY_FAULT_REG_LEN >= PAGE_SIZE ||
    1.19 +         ecap_iotlb_offset(iommu->ecap) >= PAGE_SIZE )
    1.20 +    {
    1.21 +        dprintk(XENLOG_ERR VTDPREFIX, "IOMMU: unsupported\n");
    1.22 +        print_iommu_regs(drhd);
    1.23 +        return -ENODEV;
    1.24 +    }
    1.25  
    1.26      /* Calculate number of pagetable levels: between 2 and 4. */
    1.27      sagaw = cap_sagaw(iommu->cap);
    1.28 @@ -1081,7 +1093,7 @@ static int iommu_alloc(struct acpi_drhd_
    1.29      {
    1.30          dprintk(XENLOG_ERR VTDPREFIX,
    1.31                   "IOMMU: unsupported sagaw %lx\n", sagaw);
    1.32 -        xfree(iommu);
    1.33 +        print_iommu_regs(drhd);
    1.34          return -ENODEV;
    1.35      }
    1.36      iommu->nr_pt_levels = agaw_to_level(agaw);
    1.37 @@ -1111,7 +1123,6 @@ static int iommu_alloc(struct acpi_drhd_
    1.38      spin_lock_init(&iommu->lock);
    1.39      spin_lock_init(&iommu->register_lock);
    1.40  
    1.41 -    drhd->iommu = iommu;
    1.42      return 0;
    1.43  }
    1.44  
    1.45 @@ -1122,6 +1133,8 @@ static void iommu_free(struct acpi_drhd_
    1.46      if ( iommu == NULL )
    1.47          return;
    1.48  
    1.49 +    drhd->iommu = NULL;
    1.50 +
    1.51      if ( iommu->root_maddr != 0 )
    1.52      {
    1.53          free_pgtable_maddr(iommu->root_maddr);
    1.54 @@ -1135,10 +1148,9 @@ static void iommu_free(struct acpi_drhd_
    1.55      xfree(iommu->domid_map);
    1.56  
    1.57      free_intel_iommu(iommu->intel);
    1.58 -    destroy_irq(iommu->irq);
    1.59 +    if ( iommu->irq >= 0 )
    1.60 +        destroy_irq(iommu->irq);
    1.61      xfree(iommu);
    1.62 -
    1.63 -    drhd->iommu = NULL;
    1.64  }
    1.65  
    1.66  #define guestwidth_to_adjustwidth(gaw) ({       \
    1.67 @@ -1765,13 +1777,8 @@ void clear_fault_bits(struct iommu *iomm
    1.68      unsigned long flags;
    1.69  
    1.70      spin_lock_irqsave(&iommu->register_lock, flags);
    1.71 -    val = dmar_readq(
    1.72 -        iommu->reg,
    1.73 -        cap_fault_reg_offset(dmar_readq(iommu->reg,DMAR_CAP_REG))+0x8);
    1.74 -    dmar_writeq(
    1.75 -        iommu->reg,
    1.76 -        cap_fault_reg_offset(dmar_readq(iommu->reg,DMAR_CAP_REG))+8,
    1.77 -        val);
    1.78 +    val = dmar_readq(iommu->reg, cap_fault_reg_offset(iommu->cap) + 8);
    1.79 +    dmar_writeq(iommu->reg, cap_fault_reg_offset(iommu->cap) + 8, val);
    1.80      dmar_writel(iommu->reg, DMAR_FSTS_REG, DMA_FSTS_FAULTS);
    1.81      spin_unlock_irqrestore(&iommu->register_lock, flags);
    1.82  }
     2.1 --- a/xen/drivers/passthrough/vtd/utils.c	Thu Mar 11 17:15:27 2010 +0000
     2.2 +++ b/xen/drivers/passthrough/vtd/utils.c	Thu Mar 11 17:15:54 2010 +0000
     2.3 @@ -59,45 +59,28 @@ void disable_pmr(struct iommu *iommu)
     2.4  void print_iommu_regs(struct acpi_drhd_unit *drhd)
     2.5  {
     2.6      struct iommu *iommu = drhd->iommu;
     2.7 +    u64 cap;
     2.8  
     2.9      printk("---- print_iommu_regs ----\n");
    2.10 -    printk("print_iommu_regs: drhd->address = %"PRIx64"\n", drhd->address);
    2.11 -    printk("print_iommu_regs: DMAR_VER_REG = %x\n",
    2.12 -           dmar_readl(iommu->reg,DMAR_VER_REG));
    2.13 -    printk("print_iommu_regs: DMAR_CAP_REG = %"PRIx64"\n",
    2.14 -           dmar_readq(iommu->reg,DMAR_CAP_REG));
    2.15 -    printk("print_iommu_regs: n_fault_reg = %"PRIx64"\n",
    2.16 -           cap_num_fault_regs(dmar_readq(iommu->reg, DMAR_CAP_REG)));
    2.17 -    printk("print_iommu_regs: fault_recording_offset_l = %"PRIx64"\n",
    2.18 -           cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)));
    2.19 -    printk("print_iommu_regs: fault_recording_offset_h = %"PRIx64"\n",
    2.20 -           cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8);
    2.21 -    printk("print_iommu_regs: fault_recording_reg_l = %"PRIx64"\n",
    2.22 -           dmar_readq(iommu->reg,
    2.23 -               cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG))));
    2.24 -    printk("print_iommu_regs: fault_recording_reg_h = %"PRIx64"\n",
    2.25 -           dmar_readq(iommu->reg,
    2.26 -               cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8));
    2.27 -    printk("print_iommu_regs: DMAR_ECAP_REG = %"PRIx64"\n",
    2.28 -           dmar_readq(iommu->reg,DMAR_ECAP_REG));
    2.29 -    printk("print_iommu_regs: DMAR_GCMD_REG = %x\n",
    2.30 -           dmar_readl(iommu->reg,DMAR_GCMD_REG));
    2.31 -    printk("print_iommu_regs: DMAR_GSTS_REG = %x\n",
    2.32 -           dmar_readl(iommu->reg,DMAR_GSTS_REG));
    2.33 -    printk("print_iommu_regs: DMAR_RTADDR_REG = %"PRIx64"\n",
    2.34 -           dmar_readq(iommu->reg,DMAR_RTADDR_REG));
    2.35 -    printk("print_iommu_regs: DMAR_CCMD_REG = %"PRIx64"\n",
    2.36 -           dmar_readq(iommu->reg,DMAR_CCMD_REG));
    2.37 -    printk("print_iommu_regs: DMAR_FSTS_REG = %x\n",
    2.38 -           dmar_readl(iommu->reg,DMAR_FSTS_REG));
    2.39 -    printk("print_iommu_regs: DMAR_FECTL_REG = %x\n",
    2.40 -           dmar_readl(iommu->reg,DMAR_FECTL_REG));
    2.41 -    printk("print_iommu_regs: DMAR_FEDATA_REG = %x\n",
    2.42 -           dmar_readl(iommu->reg,DMAR_FEDATA_REG));
    2.43 -    printk("print_iommu_regs: DMAR_FEADDR_REG = %x\n",
    2.44 -           dmar_readl(iommu->reg,DMAR_FEADDR_REG));
    2.45 -    printk("print_iommu_regs: DMAR_FEUADDR_REG = %x\n",
    2.46 -           dmar_readl(iommu->reg,DMAR_FEUADDR_REG));
    2.47 +    printk(" drhd->address = %"PRIx64"\n", drhd->address);
    2.48 +    printk(" VER = %x\n", dmar_readl(iommu->reg, DMAR_VER_REG));
    2.49 +    printk(" CAP = %"PRIx64"\n", cap = dmar_readq(iommu->reg, DMAR_CAP_REG));
    2.50 +    printk(" n_fault_reg = %"PRIx64"\n", cap_num_fault_regs(cap));
    2.51 +    printk(" fault_recording_offset = %"PRIx64"\n", cap_fault_reg_offset(cap));
    2.52 +    printk(" fault_recording_reg_l = %"PRIx64"\n",
    2.53 +           dmar_readq(iommu->reg, cap_fault_reg_offset(cap)));
    2.54 +    printk(" fault_recording_reg_h = %"PRIx64"\n",
    2.55 +           dmar_readq(iommu->reg, cap_fault_reg_offset(cap) + 8));
    2.56 +    printk(" ECAP = %"PRIx64"\n", dmar_readq(iommu->reg, DMAR_ECAP_REG));
    2.57 +    printk(" GCMD = %x\n", dmar_readl(iommu->reg, DMAR_GCMD_REG));
    2.58 +    printk(" GSTS = %x\n", dmar_readl(iommu->reg, DMAR_GSTS_REG));
    2.59 +    printk(" RTADDR = %"PRIx64"\n", dmar_readq(iommu->reg,DMAR_RTADDR_REG));
    2.60 +    printk(" CCMD = %"PRIx64"\n", dmar_readq(iommu->reg, DMAR_CCMD_REG));
    2.61 +    printk(" FSTS = %x\n", dmar_readl(iommu->reg, DMAR_FSTS_REG));
    2.62 +    printk(" FECTL = %x\n", dmar_readl(iommu->reg, DMAR_FECTL_REG));
    2.63 +    printk(" FEDATA = %x\n", dmar_readl(iommu->reg, DMAR_FEDATA_REG));
    2.64 +    printk(" FEADDR = %x\n", dmar_readl(iommu->reg, DMAR_FEADDR_REG));
    2.65 +    printk(" FEUADDR = %x\n", dmar_readl(iommu->reg, DMAR_FEUADDR_REG));
    2.66  }
    2.67  
    2.68  static u32 get_level_index(unsigned long gmfn, int level)