[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 Fri, May 12, 2017 at 07:42:51AM -0600, Jan Beulich wrote:
> >>> 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 ...

Yes, I modify pt_irq_destroy_bind to return EOPNOTSUPP when trying to unbind
such an interrupt. I can implement the unbind, but it's not going to be used
ATM.

> > --- 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().

OK, changed.

> > +    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.

I've added this because hvm_gsi_assert doesn't call assert_irq, so a PIC would
not work properly, but it's probably pointless.

> > +    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()).

__hvm_pci_intx_{de}assert has an array that tracks the status of each interrupt
line, and Xen does the routing based on that (the __test_and_clear_bit at the
top of __hvm_pci_intx_assert). That prevents the same line from triggering
multiple times, which is not available here, and thus Xen needs to rely on
gsi_assert_count in order to know if the GSI is pending or not.

Switched to use a set to 1/0 instead of the increment, which I agree makes this
clearer.

> 
> > @@ -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."

Fixed, thanks.

> > @@ -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.

OK, let me return error instead to be on the safe side then.

> > @@ -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.

AFAICT max length should be 21, would you be fine with me setting it to 24 to
be safe?

> 
> > @@ -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.

OK, I've removed this and fixed the function so it can unbind
HVM_IRQ_DPCI_IDENTITY_GSI.

> > @@ -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.

I've left it in it's previous place and added a !is_hardware_domain check.

> > @@ -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.

Done.

> 
> >                             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?

Hm, I don't think it's needed, probably just a leftover from when I was testing
the patches.

> > @@ -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.

I will leave the others as they are, or else they should be changed in a
separate patch.

> > +                          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.

Done.

Thanks for the review, Roger.


_______________________________________________
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®.