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

Re: [Xen-devel] [PATCH v2 2/3] x86/pt: enable binding of GSIs to a PVH Dom0



>>> On 19.04.17 at 17:11, <roger.pau@xxxxxxxxxx> wrote:
> Note that currently there's no support for unbinding this interrupts.

Do you plan to deal with that before this changes goes in? Aiui this
not working means you can't pass through devices with pin based
interrupts once Dom0 chose to bind to them. Otoh hand you modify
pt_irq_destroy_bind(), so I'm a little puzzled ...

> --- a/xen/arch/x86/hvm/irq.c
> +++ b/xen/arch/x86/hvm/irq.c
> @@ -126,6 +126,34 @@ void hvm_pci_intx_deassert(
>      spin_unlock(&d->arch.hvm_domain.irq_lock);
>  }
>  
> +void hvm_gsi_assert(struct domain *d, unsigned int gsi)
> +{
> +    struct hvm_irq *hvm_irq = hvm_domain_irq(d);
> +
> +    ASSERT(gsi < hvm_irq->nr_gsis);

This would probably better match the alternative construct in
__hvm_pci_intx_assert().

> +    ASSERT(!has_vpic(d));

This doesn't look to be relevant for the rest of the function. Is there
a particular reason you've added it? If so, a brief comment might
help.

> +    spin_lock(&d->arch.hvm_domain.irq_lock);
> +    if ( !hvm_irq->gsi_assert_count[gsi] )
> +    {
> +        hvm_irq->gsi_assert_count[gsi]++;

Why is this an increment instead of a simple write of 1? Or the
other way around - why is this not always incrementing, just like
__hvm_pci_intx_assert() does? (Symmetric questions then for
hvm_gsi_deassert()).

> @@ -274,10 +289,16 @@ int pt_irq_create_bind(
>      spin_lock(&d->event_lock);
>  
>      hvm_irq_dpci = domain_get_irq_dpci(d);
> -    if ( hvm_irq_dpci == NULL )
> +    if ( hvm_irq_dpci == NULL && !is_hardware_domain(d) )
>      {
>          unsigned int i;
>  
> +        /*
> +         * NB: the hardware domain doesn't use a hvm_irq_dpci struct because
> +         * it's only allowed to identity map GSIs, and so the data contained 
> in
> +         * that struct (used to map guest GSIs into machine GSIs and perform
> +         * interrupt routing) it's completely useless for it.

"...) is completely useless to it."

> @@ -422,35 +443,51 @@ int pt_irq_create_bind(
>      case PT_IRQ_TYPE_PCI:
>      case PT_IRQ_TYPE_MSI_TRANSLATE:
>      {
> -        unsigned int bus = pt_irq_bind->u.pci.bus;
> -        unsigned int device = pt_irq_bind->u.pci.device;
> -        unsigned int intx = pt_irq_bind->u.pci.intx;
> -        unsigned int guest_gsi = hvm_pci_intx_gsi(device, intx);
> -        unsigned int link = hvm_pci_intx_link(device, intx);
> -        struct dev_intx_gsi_link *digl = xmalloc(struct dev_intx_gsi_link);
> -        struct hvm_girq_dpci_mapping *girq =
> -            xmalloc(struct hvm_girq_dpci_mapping);
> +        struct dev_intx_gsi_link *digl = NULL;
> +        struct hvm_girq_dpci_mapping *girq = NULL;
> +        unsigned int guest_gsi;
>  
> -        if ( !digl || !girq )
> +        /*
> +         * Mapping GSIs for the hardware domain is different than doing it 
> for
> +         * an unpriviledged guest, the hardware domain is only allowed to
> +         * identity map GSIs, and as such all the data in the u.pci union is
> +         * discarded.
> +         */
> +        if ( !is_hardware_domain(d) )
>          {
> -            spin_unlock(&d->event_lock);
> -            xfree(girq);
> -            xfree(digl);
> -            return -ENOMEM;
> -        }
> +            unsigned int link;
> +
> +            digl = xmalloc(struct dev_intx_gsi_link);
> +            girq = xmalloc(struct hvm_girq_dpci_mapping);
> +
> +            if ( !digl || !girq )
> +            {
> +                spin_unlock(&d->event_lock);
> +                xfree(girq);
> +                xfree(digl);
> +                return -ENOMEM;
> +            }
> +
> +            girq->bus = digl->bus = pt_irq_bind->u.pci.bus;
> +            girq->device = digl->device = pt_irq_bind->u.pci.device;
> +            girq->intx = digl->intx = pt_irq_bind->u.pci.intx;
> +            list_add_tail(&digl->list, &pirq_dpci->digl_list);
>  
> -        hvm_irq_dpci->link_cnt[link]++;
> +            guest_gsi = hvm_pci_intx_gsi(digl->device, digl->intx);
> +            link = hvm_pci_intx_link(digl->device, digl->intx);
>  
> -        digl->bus = bus;
> -        digl->device = device;
> -        digl->intx = intx;
> -        list_add_tail(&digl->list, &pirq_dpci->digl_list);
> +            hvm_irq_dpci->link_cnt[link]++;
>  
> -        girq->bus = bus;
> -        girq->device = device;
> -        girq->intx = intx;
> -        girq->machine_gsi = pirq;
> -        list_add_tail(&girq->list, &hvm_irq_dpci->girq[guest_gsi]);
> +            girq->machine_gsi = pirq;
> +            list_add_tail(&girq->list, &hvm_irq_dpci->girq[guest_gsi]);
> +        }
> +        else
> +        {
> +            /* MSI_TRANSLATE is not supported by the hardware domain. */
> +            ASSERT(pt_irq_bind->irq_type == PT_IRQ_TYPE_PCI);
> +            guest_gsi = pirq;
> +            ASSERT(guest_gsi < hvm_domain_irq(d)->nr_gsis);
> +        }

This is dangerous: For one it is impossible to judge the correctness
of at least the first of these assertions for the hwdom case without
looking at patch 3. And then the domctl path leading here does not
exclude the subject domain equaling the calling one, i.e. you
potentially assert guest input correctness here. Yes, we have XSA-77
in place, but no, we shouldn't introduce new issues anywhere unless
that's entirely unavoidable.

> @@ -504,10 +567,18 @@ int pt_irq_create_bind(
>          spin_unlock(&d->event_lock);
>  
>          if ( iommu_verbose )
> -            printk(XENLOG_G_INFO
> -                   "d%d: bind: m_gsi=%u g_gsi=%u dev=%02x.%02x.%u intx=%u\n",
> -                   d->domain_id, pirq, guest_gsi, bus,
> -                   PCI_SLOT(device), PCI_FUNC(device), intx);
> +        {
> +            char buf[50];
> +
> +            if ( !is_hardware_domain(d) )
> +                snprintf(buf, ARRAY_SIZE(buf), " dev=%02x.%02x.%u intx=%u",
> +                         digl->bus, PCI_SLOT(digl->device),
> +                         PCI_FUNC(digl->device), digl->intx);

The buffer array seems heavily over-sized - my counting gives at best
slightly over 20 characters you actually need.

> @@ -522,7 +593,6 @@ int pt_irq_create_bind(
>  int pt_irq_destroy_bind(
>      struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
>  {
> -    struct hvm_irq_dpci *hvm_irq_dpci;
>      struct hvm_pirq_dpci *pirq_dpci;
>      unsigned int machine_gsi = pt_irq_bind->machine_irq;
>      struct pirq *pirq;
> @@ -552,17 +622,15 @@ int pt_irq_destroy_bind(
>  
>      spin_lock(&d->event_lock);
>  
> -    hvm_irq_dpci = domain_get_irq_dpci(d);
> -
> -    if ( hvm_irq_dpci == NULL )
> +    pirq = pirq_info(d, machine_gsi);
> +    pirq_dpci = pirq_dpci(pirq);
> +    if ( pirq_dpci->flags & HVM_IRQ_DPCI_IDENTITY_GSI )

I'm sure we've discussed aspects of this before: pirq_dpci may be
NULL here, i.e. you can't blindly dereference it. All other uses in
the function indeed have a NULL check first.

> @@ -570,9 +638,16 @@ int pt_irq_destroy_bind(
>          unsigned int intx = pt_irq_bind->u.pci.intx;
>          unsigned int guest_gsi = hvm_pci_intx_gsi(device, intx);
>          unsigned int link = hvm_pci_intx_link(device, intx);
> +        struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d);
>          struct hvm_girq_dpci_mapping *girq;
>          struct dev_intx_gsi_link *digl, *tmp;
>  
> +        if ( hvm_irq_dpci == NULL )
> +        {
> +            spin_unlock(&d->event_lock);
> +            return -EINVAL;
> +        }

Moving this check here is a behavioral modification. Perhaps a
good one, yet it doesn't belong into this patch. Instead it should
be properly reasoned about in a separate patch, if it is a correct
thing to do.

> @@ -814,17 +896,12 @@ static void hvm_dirq_assist(struct domain *d, struct 
> hvm_pirq_dpci *pirq_dpci)
>      spin_unlock(&d->event_lock);
>  }
>  
> -static void __hvm_dpci_eoi(struct domain *d,
> -                           const struct hvm_girq_dpci_mapping *girq,
> +static void __hvm_pirq_eoi(struct pirq *pirq,

Please drop the double leading underscores.

>                             const union vioapic_redir_entry *ent)
>  {
> -    struct pirq *pirq = pirq_info(d, girq->machine_gsi);
> -    struct hvm_pirq_dpci *pirq_dpci;
> -
> -    if ( !hvm_domain_use_pirq(d, pirq) )
> -        hvm_pci_intx_deassert(d, girq->device, girq->intx);
> +    struct hvm_pirq_dpci *pirq_dpci = pirq_dpci(pirq);
>  
> -    pirq_dpci = pirq_dpci(pirq);
> +    ASSERT(pirq_dpci);

Why is this useful / needed all of the sudden?

> @@ -839,6 +916,32 @@ static void __hvm_dpci_eoi(struct domain *d,
>      pirq_guest_eoi(pirq);
>  }
>  
> +static void __hvm_dpci_eoi(struct domain *d,
> +                           const struct hvm_girq_dpci_mapping *girq,
> +                           const union vioapic_redir_entry *ent)
> +{
> +    struct pirq *pirq = pirq_info(d, girq->machine_gsi);
> +
> +    if ( !hvm_domain_use_pirq(d, pirq) )
> +        hvm_pci_intx_deassert(d, girq->device, girq->intx);
> +
> +    __hvm_pirq_eoi(pirq, ent);
> +}
> +
> +static void __hvm_gsi_eoi(struct domain *d, unsigned int gsi,

Same here for the double underscores. For the pre-existing
function I'd leave it up to you whether to also drop them. What
I care about is that we don't gain new non-conforming names.

> +                          const union vioapic_redir_entry *ent)
> +{
> +    struct pirq *pirq = pirq_info(d, gsi);
> +    struct hvm_pirq_dpci *pirq_dpci = pirq_dpci(pirq);
> +
> +    /* Check if GSI is actually mapped. */
> +    if ( !pirq_dpci )

Please avoid the local variable when used just once here.

Jan

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.