ia64/xen-unstable

changeset 15928:aad813d8a8ad

PCI passthru: VT-d I/O hooks.
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
Signed-off-by: Guy Zana <guy@neocleus.com>
author kfraser@localhost.localdomain
date Wed Sep 19 09:12:06 2007 +0100 (2007-09-19)
parents b7eb2bb9b625
children 45548c83daef
files xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/intercept.c xen/arch/x86/hvm/io.c xen/arch/x86/hvm/vmx/vtd/intel-iommu.c xen/arch/x86/hvm/vmx/vtd/io.c xen/drivers/acpi/tables.c xen/include/asm-x86/hvm/iommu.h xen/include/asm-x86/iommu.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hvm.c	Tue Sep 18 16:09:19 2007 +0100
     1.2 +++ b/xen/arch/x86/hvm/hvm.c	Wed Sep 19 09:12:06 2007 +0100
     1.3 @@ -48,6 +48,7 @@
     1.4  #include <public/hvm/ioreq.h>
     1.5  #include <public/version.h>
     1.6  #include <public/memory.h>
     1.7 +#include <asm/iommu.h>
     1.8  
     1.9  int hvm_enabled __read_mostly;
    1.10  
    1.11 @@ -215,6 +216,10 @@ int hvm_domain_initialise(struct domain 
    1.12      spin_lock_init(&d->arch.hvm_domain.pbuf_lock);
    1.13      spin_lock_init(&d->arch.hvm_domain.irq_lock);
    1.14  
    1.15 +    rc = iommu_domain_init(d);
    1.16 +    if ( rc != 0 )
    1.17 +        return rc;
    1.18 +
    1.19      rc = paging_enable(d, PG_refcounts|PG_translate|PG_external);
    1.20      if ( rc != 0 )
    1.21          return rc;
     2.1 --- a/xen/arch/x86/hvm/intercept.c	Tue Sep 18 16:09:19 2007 +0100
     2.2 +++ b/xen/arch/x86/hvm/intercept.c	Wed Sep 19 09:12:06 2007 +0100
     2.3 @@ -29,6 +29,7 @@
     2.4  #include <asm/current.h>
     2.5  #include <io_ports.h>
     2.6  #include <xen/event.h>
     2.7 +#include <asm/iommu.h>
     2.8  
     2.9  
    2.10  extern struct hvm_mmio_handler hpet_mmio_handler;
    2.11 @@ -243,6 +244,9 @@ int hvm_io_intercept(ioreq_t *p, int typ
    2.12      int i;
    2.13      unsigned long addr, size;
    2.14  
    2.15 +    if ( (type == HVM_PORTIO) && (dpci_ioport_intercept(p)) )
    2.16 +        return 1;
    2.17 +
    2.18      for (i = 0; i < handler->num_slot; i++) {
    2.19          if( type != handler->hdl_list[i].type)
    2.20              continue;
     3.1 --- a/xen/arch/x86/hvm/io.c	Tue Sep 18 16:09:19 2007 +0100
     3.2 +++ b/xen/arch/x86/hvm/io.c	Wed Sep 19 09:12:06 2007 +0100
     3.3 @@ -42,6 +42,7 @@
     3.4  #include <asm/hvm/vlapic.h>
     3.5  
     3.6  #include <public/sched.h>
     3.7 +#include <xen/iocap.h>
     3.8  #include <public/hvm/ioreq.h>
     3.9  
    3.10  #if defined (__i386__)
    3.11 @@ -864,6 +865,123 @@ void hvm_io_assist(void)
    3.12      vcpu_end_shutdown_deferral(v);
    3.13  }
    3.14  
    3.15 +void dpci_ioport_read(uint32_t mport, ioreq_t *p)
    3.16 +{
    3.17 +    uint64_t i;
    3.18 +    uint64_t z_data;
    3.19 +    uint64_t length = (p->count * p->size);
    3.20 +
    3.21 +    for ( i = 0; i < length; i += p->size )
    3.22 +    {
    3.23 +        z_data = ~0ULL;
    3.24 +        
    3.25 +        switch ( p->size )
    3.26 +        {
    3.27 +        case BYTE:
    3.28 +            z_data = (uint64_t)inb(mport);
    3.29 +            break;
    3.30 +        case WORD:
    3.31 +            z_data = (uint64_t)inw(mport);
    3.32 +            break;
    3.33 +        case LONG:
    3.34 +            z_data = (uint64_t)inl(mport);
    3.35 +            break;
    3.36 +        default:
    3.37 +            gdprintk(XENLOG_ERR, "Error: unable to handle size: %"
    3.38 +                     PRId64 "\n", p->size);
    3.39 +            return;
    3.40 +        }
    3.41 +
    3.42 +        p->data = z_data;
    3.43 +        if ( p->data_is_ptr &&
    3.44 +             hvm_copy_to_guest_phys(p->data + i, (void *)&z_data,
    3.45 +                                    (int)p->size) )
    3.46 +        {
    3.47 +            gdprintk(XENLOG_ERR, "Error: couldn't copy to hvm phys\n");
    3.48 +            return;
    3.49 +        }
    3.50 +    }
    3.51 +}
    3.52 +
    3.53 +void dpci_ioport_write(uint32_t mport, ioreq_t *p)
    3.54 +{
    3.55 +    uint64_t i;
    3.56 +    uint64_t z_data = 0;
    3.57 +    uint64_t length = (p->count * p->size);
    3.58 +
    3.59 +    for ( i = 0; i < length; i += p->size )
    3.60 +    {
    3.61 +        z_data = p->data;
    3.62 +        if ( p->data_is_ptr &&
    3.63 +             hvm_copy_from_guest_phys((void *)&z_data,
    3.64 +                                      p->data + i, (int)p->size) )
    3.65 +        {
    3.66 +            gdprintk(XENLOG_ERR, "Error: couldn't copy from hvm phys\n");
    3.67 +            return;
    3.68 +        }
    3.69 +
    3.70 +        switch ( p->size )
    3.71 +        {
    3.72 +        case BYTE:
    3.73 +            outb((uint8_t) z_data, mport);
    3.74 +            break;
    3.75 +        case WORD:
    3.76 +            outw((uint16_t) z_data, mport);
    3.77 +            break;
    3.78 +        case LONG:
    3.79 +            outl((uint32_t) z_data, mport);
    3.80 +            break;
    3.81 +        default:
    3.82 +            gdprintk(XENLOG_ERR, "Error: unable to handle size: %"
    3.83 +                     PRId64 "\n", p->size);
    3.84 +            break;
    3.85 +        }
    3.86 +    }
    3.87 +}
    3.88 +
    3.89 +int dpci_ioport_intercept(ioreq_t *p)
    3.90 +{
    3.91 +    struct domain *d = current->domain;
    3.92 +    struct hvm_iommu *hd = domain_hvm_iommu(d);
    3.93 +    struct g2m_ioport *g2m_ioport;
    3.94 +    unsigned int mport, gport = p->addr;
    3.95 +    unsigned int s = 0, e = 0;
    3.96 +
    3.97 +    list_for_each_entry( g2m_ioport, &hd->g2m_ioport_list, list )
    3.98 +    {
    3.99 +        s = g2m_ioport->gport;
   3.100 +        e = s + g2m_ioport->np;
   3.101 +        if ( (gport >= s) && (gport < e) )
   3.102 +            goto found;
   3.103 +    }
   3.104 +
   3.105 +    return 0;
   3.106 +
   3.107 + found:
   3.108 +    mport = (gport - s) + g2m_ioport->mport;
   3.109 +
   3.110 +    if ( !ioports_access_permitted(d, mport, mport + p->size - 1) ) 
   3.111 +    {
   3.112 +        gdprintk(XENLOG_ERR, "Error: access to gport=0x%x denied!\n",
   3.113 +                 (uint32_t)p->addr);
   3.114 +        return 0;
   3.115 +    }
   3.116 +
   3.117 +    switch ( p->dir )
   3.118 +    {
   3.119 +    case IOREQ_READ:
   3.120 +        dpci_ioport_read(mport, p);
   3.121 +        break;
   3.122 +    case IOREQ_WRITE:
   3.123 +        dpci_ioport_write(mport, p);
   3.124 +        break;
   3.125 +    default:
   3.126 +        gdprintk(XENLOG_ERR, "Error: couldn't handle p->dir = %d", p->dir);
   3.127 +    }
   3.128 +
   3.129 +    return 1;
   3.130 +}
   3.131 +
   3.132  /*
   3.133   * Local variables:
   3.134   * mode: C
     4.1 --- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c	Tue Sep 18 16:09:19 2007 +0100
     4.2 +++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c	Wed Sep 19 09:12:06 2007 +0100
     4.3 @@ -929,18 +929,16 @@ int iommu_domain_init(struct domain *dom
     4.4      unsigned long sagaw;
     4.5      struct acpi_drhd_unit *drhd;
     4.6  
     4.7 -    if (list_empty(&acpi_drhd_units))
     4.8 -        return 0;
     4.9      spin_lock_init(&hd->mapping_lock);
    4.10      spin_lock_init(&hd->iommu_list_lock);
    4.11      INIT_LIST_HEAD(&hd->pdev_list);
    4.12 +    INIT_LIST_HEAD(&hd->g2m_ioport_list);
    4.13  
    4.14 -    for_each_drhd_unit(drhd) {
    4.15 -        if (drhd->iommu)
    4.16 -            iommu = drhd->iommu;
    4.17 -        else
    4.18 -            iommu = iommu_alloc(drhd);
    4.19 -    }
    4.20 +    if ( !vtd_enabled || list_empty(&acpi_drhd_units) )
    4.21 +        return 0;
    4.22 +
    4.23 +    for_each_drhd_unit ( drhd )
    4.24 +        iommu = drhd->iommu ? : iommu_alloc(drhd);
    4.25  
    4.26      /* calculate AGAW */
    4.27      if (guest_width > cap_mgaw(iommu->cap))
    4.28 @@ -949,7 +947,8 @@ int iommu_domain_init(struct domain *dom
    4.29      agaw = width_to_agaw(adjust_width);
    4.30      /* FIXME: hardware doesn't support it, choose a bigger one? */
    4.31      sagaw = cap_sagaw(iommu->cap);
    4.32 -    if (!test_bit(agaw, &sagaw)) {
    4.33 +    if ( !test_bit(agaw, &sagaw) )
    4.34 +    {
    4.35          gdprintk(XENLOG_ERR VTDPREFIX,
    4.36              "IOMMU: hardware doesn't support the agaw\n");
    4.37          agaw = find_next_bit(&sagaw, 5, agaw);
     5.1 --- a/xen/arch/x86/hvm/vmx/vtd/io.c	Tue Sep 18 16:09:19 2007 +0100
     5.2 +++ b/xen/arch/x86/hvm/vmx/vtd/io.c	Wed Sep 19 09:12:06 2007 +0100
     5.3 @@ -43,7 +43,39 @@
     5.4  #include <public/sched.h>
     5.5  #include <xen/iocap.h>
     5.6  #include <public/hvm/ioreq.h>
     5.7 +#include <public/domctl.h>
     5.8  
     5.9 +int pt_irq_create_bind_vtd(
    5.10 +    struct domain *d,
    5.11 +    xen_domctl_bind_pt_irq_t * pt_irq_bind)
    5.12 +{
    5.13 +    struct hvm_domain *hd = &d->arch.hvm_domain;
    5.14 +    uint32_t machine_gsi, guest_gsi;
    5.15 +    uint32_t device, intx;
    5.16 +
    5.17 +    machine_gsi = pt_irq_bind->machine_irq;
    5.18 +    device = pt_irq_bind->u.pci.device;
    5.19 +    intx = pt_irq_bind->u.pci.intx;
    5.20 +    guest_gsi = hvm_pci_intx_gsi(device, intx);
    5.21 +
    5.22 +    hd->irq.mirq[machine_gsi].valid = 1;
    5.23 +    hd->irq.mirq[machine_gsi].device = device;
    5.24 +    hd->irq.mirq[machine_gsi].intx = intx;
    5.25 +    hd->irq.mirq[machine_gsi].guest_gsi = guest_gsi;
    5.26 +
    5.27 +    hd->irq.girq[guest_gsi].valid = 1;
    5.28 +    hd->irq.girq[guest_gsi].device = device;
    5.29 +    hd->irq.girq[guest_gsi].intx = intx;
    5.30 +    hd->irq.girq[guest_gsi].machine_gsi = machine_gsi;
    5.31 +
    5.32 +    /* Deal with gsi for legacy devices */
    5.33 +    pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
    5.34 +    gdprintk(XENLOG_ERR,
    5.35 +        "XEN_DOMCTL_irq_mapping: m_irq = %x device = %x intx = %x\n",
    5.36 +        machine_gsi, device, intx);
    5.37 +
    5.38 +    return 0;
    5.39 +}
    5.40  int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
    5.41  {
    5.42      uint32_t device, intx;
     6.1 --- a/xen/drivers/acpi/tables.c	Tue Sep 18 16:09:19 2007 +0100
     6.2 +++ b/xen/drivers/acpi/tables.c	Wed Sep 19 09:12:06 2007 +0100
     6.3 @@ -59,6 +59,7 @@ static char *acpi_table_signatures[ACPI_
     6.4  	[ACPI_SPMI] = "SPMI",
     6.5  	[ACPI_HPET] = "HPET",
     6.6  	[ACPI_MCFG] = "MCFG",
     6.7 +	[ACPI_DMAR] = "DMAR",
     6.8  };
     6.9  
    6.10  static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
     7.1 --- a/xen/include/asm-x86/hvm/iommu.h	Tue Sep 18 16:09:19 2007 +0100
     7.2 +++ b/xen/include/asm-x86/hvm/iommu.h	Wed Sep 19 09:12:06 2007 +0100
     7.3 @@ -28,6 +28,13 @@
     7.4  #include <public/hvm/params.h>
     7.5  #include <public/hvm/save.h>
     7.6  
     7.7 +struct g2m_ioport {
     7.8 +    struct list_head list;
     7.9 +    unsigned int gport;
    7.10 +    unsigned int mport;
    7.11 +    unsigned int np;
    7.12 +};
    7.13 +
    7.14  struct hvm_iommu {
    7.15      spinlock_t iommu_list_lock;    /* protect iommu specific lists */
    7.16      struct list_head pdev_list;    /* direct accessed pci devices */
     8.1 --- a/xen/include/asm-x86/iommu.h	Tue Sep 18 16:09:19 2007 +0100
     8.2 +++ b/xen/include/asm-x86/iommu.h	Wed Sep 19 09:12:06 2007 +0100
     8.3 @@ -28,6 +28,7 @@
     8.4  #include <xen/xmalloc.h>
     8.5  #include <asm/hvm/vmx/intel-iommu.h>
     8.6  #include <public/hvm/ioreq.h>
     8.7 +#include <public/domctl.h>
     8.8  
     8.9  extern int vtd_enabled;
    8.10  
    8.11 @@ -75,5 +76,9 @@ void iommu_flush(struct domain *d, dma_a
    8.12  void iommu_set_pgd(struct domain *d);
    8.13  void iommu_domain_teardown(struct domain *d);
    8.14  int hvm_do_IRQ_dpci(struct domain *d, unsigned int irq);
    8.15 +int dpci_ioport_intercept(ioreq_t *p);
    8.16 +int pt_irq_create_bind_vtd(struct domain *d,
    8.17 +    xen_domctl_bind_pt_irq_t * pt_irq_bind);
    8.18 +
    8.19  
    8.20  #endif // _IOMMU_H_