ia64/xen-unstable

changeset 17591:fb58da516749

VT-d: Fix free VT-d page table issue

This patch frees VT-d page tables from pgd, rather than free them
according to a guest address range.

This fixes [Bug 1244] Poweroff/Destroying HVM guest causes HV
crash. http://bugzilla.xensource.com/bugzilla/show_bug.cgi?id=1244.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed May 07 09:19:40 2008 +0100 (2008-05-07)
parents 9d2a45d4b6c6
children 2cc926c18a7b
files xen/drivers/passthrough/vtd/iommu.c xen/drivers/passthrough/vtd/iommu.h
line diff
     1.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Wed May 07 09:17:52 2008 +0100
     1.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Wed May 07 09:19:40 2008 +0100
     1.3 @@ -678,17 +678,63 @@ void dma_pte_free_pagetable(struct domai
     1.4      }
     1.5  }
     1.6  
     1.7 - /* free all VT-d page tables when shut down or destroy domain. */
     1.8 +static void iommu_free_next_pagetable(u64 pt_maddr, unsigned long index,
     1.9 +                                      int level)
    1.10 +{
    1.11 +    struct acpi_drhd_unit *drhd;
    1.12 +    unsigned long next_index;
    1.13 +    struct dma_pte *pt_vaddr, *pde;
    1.14 +    int next_level;
    1.15 +
    1.16 +    if ( pt_maddr == 0 )
    1.17 +        return;
    1.18 +
    1.19 +    pt_vaddr = (struct dma_pte *)map_vtd_domain_page(pt_maddr);
    1.20 +    pde = &pt_vaddr[index];
    1.21 +    if ( dma_pte_addr(*pde) != 0 )
    1.22 +    {
    1.23 +        next_level = level - 1;
    1.24 +        if ( next_level > 1 )
    1.25 +        {
    1.26 +            next_index = 0;
    1.27 +            do
    1.28 +            {
    1.29 +                iommu_free_next_pagetable(pde->val,
    1.30 +                                          next_index, next_level);
    1.31 +                next_index++;
    1.32 +            } while ( next_index < PTE_NUM );
    1.33 +        }
    1.34 +
    1.35 +        dma_clear_pte(*pde);
    1.36 +        drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
    1.37 +        iommu_flush_cache_entry(drhd->iommu, pde);
    1.38 +        free_pgtable_maddr(pde->val);
    1.39 +        unmap_vtd_domain_page(pt_vaddr);
    1.40 +    }
    1.41 +    else
    1.42 +        unmap_vtd_domain_page(pt_vaddr);
    1.43 +}
    1.44 +
    1.45 +/* free all VT-d page tables when shut down or destroy domain. */
    1.46  static void iommu_free_pagetable(struct domain *domain)
    1.47  {
    1.48 +    unsigned long index;
    1.49      struct hvm_iommu *hd = domain_hvm_iommu(domain);
    1.50 -    int addr_width = agaw_to_width(hd->agaw);
    1.51 -    u64 start, end;
    1.52 +    int total_level = agaw_to_level(hd->agaw);
    1.53  
    1.54 -    start = 0;
    1.55 -    end = (((u64)1) << addr_width) - 1;
    1.56 +    if ( hd->pgd_maddr != 0 )
    1.57 +    {
    1.58 +        index = 0;
    1.59 +        do
    1.60 +        {
    1.61 +            iommu_free_next_pagetable(hd->pgd_maddr,
    1.62 +                                      index, total_level + 1);
    1.63 +            index++;
    1.64 +        } while ( index < PTE_NUM );
    1.65  
    1.66 -    dma_pte_free_pagetable(domain, start, end);
    1.67 +        free_pgtable_maddr(hd->pgd_maddr);
    1.68 +        hd->pgd_maddr = 0;
    1.69 +    }
    1.70  }
    1.71  
    1.72  static int iommu_set_root_entry(struct iommu *iommu)
     2.1 --- a/xen/drivers/passthrough/vtd/iommu.h	Wed May 07 09:17:52 2008 +0100
     2.2 +++ b/xen/drivers/passthrough/vtd/iommu.h	Wed May 07 09:19:40 2008 +0100
     2.3 @@ -235,6 +235,7 @@ struct context_entry {
     2.4  /* page table handling */
     2.5  #define LEVEL_STRIDE       (9)
     2.6  #define LEVEL_MASK         ((1 << LEVEL_STRIDE) - 1)
     2.7 +#define PTE_NUM            (1 << LEVEL_STRIDE)
     2.8  #define agaw_to_level(val) ((val) + 2)
     2.9  #define agaw_to_width(val) (30 + val * LEVEL_STRIDE)
    2.10  #define width_to_agaw(w)   ((w - 30)/LEVEL_STRIDE)