* map_domain_pirq(): pirq already mapped?
@ 2026-05-14 1:18 Jason Andryuk
2026-05-14 8:26 ` Roger Pau Monné
0 siblings, 1 reply; 4+ messages in thread
From: Jason Andryuk @ 2026-05-14 1:18 UTC (permalink / raw)
To: Xen-devel
Hi,
Early in map_domain_pirq(), we have this block:
old_irq = domain_pirq_to_irq(d, pirq);
old_pirq = domain_irq_to_pirq(d, irq);
if ( (old_irq > 0 && (old_irq != irq) ) ||
(old_pirq && (old_pirq != pirq)) )
{
dprintk(XENLOG_G_WARNING,
"dom%d: pirq %d or irq %d already mapped (%d,%d)\n",
d->domain_id, pirq, irq, old_pirq, old_irq);
return 0;
}
Why do we return 0 instead of -EEXIST? Since the pirq is not updated,
the caller doesn't know that pirq won't fire - only old_pirq. For
allocate_and_map_gsi_pirq(), the new pirq is still returned to the
caller. I would expect old_pirq to be returned so the caller knows what
to use. Am I missing something?
Thanks,
Jason
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: map_domain_pirq(): pirq already mapped?
2026-05-14 1:18 map_domain_pirq(): pirq already mapped? Jason Andryuk
@ 2026-05-14 8:26 ` Roger Pau Monné
2026-05-15 1:01 ` Jason Andryuk
0 siblings, 1 reply; 4+ messages in thread
From: Roger Pau Monné @ 2026-05-14 8:26 UTC (permalink / raw)
To: Jason Andryuk; +Cc: Xen-devel
On Wed, May 13, 2026 at 09:18:46PM -0400, Jason Andryuk wrote:
> Hi,
>
> Early in map_domain_pirq(), we have this block:
>
> old_irq = domain_pirq_to_irq(d, pirq);
> old_pirq = domain_irq_to_pirq(d, irq);
>
> if ( (old_irq > 0 && (old_irq != irq) ) ||
> (old_pirq && (old_pirq != pirq)) )
> {
> dprintk(XENLOG_G_WARNING,
> "dom%d: pirq %d or irq %d already mapped (%d,%d)\n",
> d->domain_id, pirq, irq, old_pirq, old_irq);
> return 0;
> }
>
> Why do we return 0 instead of -EEXIST? Since the pirq is not updated, the
> caller doesn't know that pirq won't fire - only old_pirq. For
> allocate_and_map_gsi_pirq(), the new pirq is still returned to the caller.
> I would expect old_pirq to be returned so the caller knows what to use. Am
> I missing something?
Looking at bfc341a65cfb2 it seems like this might have been an attempt
to keep the previous logic in ioapic_guest_write() that didn't return
an error when attempting to add/move an in use IRQ, while switching
ioapic_guest_write() to use map_domain_pirq()?
The commit description is not very helpful sadly. I think the mention
of "And this patch also makes broken NetBSD dom0 work again." is
relevant. AFAICT NetBSD will do PHYSDEVOP_apic_read -> modify RTE (ie:
set mask bit for example) -> PHYSDEVOP_apic_write. However the
semantics of those hypercalls is not symmetric. PHYSDEVOP_apic_read
will return the vector used by Xen in the RTE, while
PHYSDEVOP_apic_write expects the vector field of the RTE to contain
the pIRQ. I think this is why map_domain_pirq() was adjusted in such
a weird way, to ignore requests with bogus pIRQs and still succeed, so
that PHYSDEVOP_apic_write would also succeed. Ideally the interface
should have been adjusted so that read/modify/write cycles using
PHYSDEVOP_apic_{read,write} would work as expected (iow:
PHYSDEVOP_apic_read should have returned the pIRQ in the vector
field).
In the context of GSIs, I think we aim for Xen to always identity map
them (so IRQ == pIRQ), but there might be (or might have been)
hypercalls that could allow you to create non-identity mappings
between GSIs and pIRQs.
Explicitly looking at allocate_and_map_gsi_pirq() do you know what
causes the domain_irq_to_pirq() in allocate_pirq() to not return the
already allocated pIRQ that matches the passed IRQ?
Overall we should likely adjust map_domain_pirq() to return -EEIXST,
and then fix ioapic_guest_write() to shallow such error so we can keep
the current behavior for that specific interface.
Regards, Roger.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: map_domain_pirq(): pirq already mapped?
2026-05-14 8:26 ` Roger Pau Monné
@ 2026-05-15 1:01 ` Jason Andryuk
2026-05-15 8:35 ` Roger Pau Monné
0 siblings, 1 reply; 4+ messages in thread
From: Jason Andryuk @ 2026-05-15 1:01 UTC (permalink / raw)
To: Roger Pau Monné; +Cc: Xen-devel
Hi Roger,
Thanks for taking a look.
On 2026-05-14 04:26, Roger Pau Monné wrote:
> On Wed, May 13, 2026 at 09:18:46PM -0400, Jason Andryuk wrote:
>> Hi,
>>
>> Early in map_domain_pirq(), we have this block:
>>
>> old_irq = domain_pirq_to_irq(d, pirq);
>> old_pirq = domain_irq_to_pirq(d, irq);
>>
>> if ( (old_irq > 0 && (old_irq != irq) ) ||
>> (old_pirq && (old_pirq != pirq)) )
>> {
>> dprintk(XENLOG_G_WARNING,
>> "dom%d: pirq %d or irq %d already mapped (%d,%d)\n",
>> d->domain_id, pirq, irq, old_pirq, old_irq);
>> return 0;
>> }
>>
>> Why do we return 0 instead of -EEXIST? Since the pirq is not updated, the
>> caller doesn't know that pirq won't fire - only old_pirq. For
>> allocate_and_map_gsi_pirq(), the new pirq is still returned to the caller.
>> I would expect old_pirq to be returned so the caller knows what to use. Am
>> I missing something?
>
> Looking at bfc341a65cfb2 it seems like this might have been an attempt
> to keep the previous logic in ioapic_guest_write() that didn't return
> an error when attempting to add/move an in use IRQ, while switching
> ioapic_guest_write() to use map_domain_pirq()?
>
> The commit description is not very helpful sadly. I think the mention
> of "And this patch also makes broken NetBSD dom0 work again." is
> relevant. AFAICT NetBSD will do PHYSDEVOP_apic_read -> modify RTE (ie:
> set mask bit for example) -> PHYSDEVOP_apic_write. However the
> semantics of those hypercalls is not symmetric. PHYSDEVOP_apic_read
> will return the vector used by Xen in the RTE, while
> PHYSDEVOP_apic_write expects the vector field of the RTE to contain
> the pIRQ. I think this is why map_domain_pirq() was adjusted in such
> a weird way, to ignore requests with bogus pIRQs and still succeed, so
> that PHYSDEVOP_apic_write would also succeed. Ideally the interface
> should have been adjusted so that read/modify/write cycles using
> PHYSDEVOP_apic_{read,write} would work as expected (iow:
> PHYSDEVOP_apic_read should have returned the pIRQ in the vector
> field).
>
> In the context of GSIs, I think we aim for Xen to always identity map
> them (so IRQ == pIRQ), but there might be (or might have been)
> hypercalls that could allow you to create non-identity mappings
> between GSIs and pIRQs.
To support non-PCI passthrough with Hyperlaunch, we added code to map a
GSI to a vIOAPIC. It does not require identity mapping, and that works.
It was while testing conditions that I expected to fail that I found
the behavior.
First map:
machine A -> guest B
Then map:
machine A -> guest C "success" from the return 0
> Explicitly looking at allocate_and_map_gsi_pirq() do you know what
> causes the domain_irq_to_pirq() in allocate_pirq() to not return the
> already allocated pIRQ that matches the passed IRQ?
Well, it's PVH and I'm making up a "PIRQ" for the vIOAPIC.
> Overall we should likely adjust map_domain_pirq() to return -EEIXST,
> and then fix ioapic_guest_write() to shallow such error so we can keep
> the current behavior for that specific interface.
Having been focused on PVH, I didn't look much at the PV behavior. But
it was still surprising to see the "no-op" success.
Thanks for the pointers.
Regards,
Jason
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: map_domain_pirq(): pirq already mapped?
2026-05-15 1:01 ` Jason Andryuk
@ 2026-05-15 8:35 ` Roger Pau Monné
0 siblings, 0 replies; 4+ messages in thread
From: Roger Pau Monné @ 2026-05-15 8:35 UTC (permalink / raw)
To: Jason Andryuk; +Cc: Xen-devel
On Thu, May 14, 2026 at 09:01:28PM -0400, Jason Andryuk wrote:
> Hi Roger,
>
> Thanks for taking a look.
>
> On 2026-05-14 04:26, Roger Pau Monné wrote:
> > On Wed, May 13, 2026 at 09:18:46PM -0400, Jason Andryuk wrote:
> > > Hi,
> > >
> > > Early in map_domain_pirq(), we have this block:
> > >
> > > old_irq = domain_pirq_to_irq(d, pirq);
> > > old_pirq = domain_irq_to_pirq(d, irq);
> > >
> > > if ( (old_irq > 0 && (old_irq != irq) ) ||
> > > (old_pirq && (old_pirq != pirq)) )
> > > {
> > > dprintk(XENLOG_G_WARNING,
> > > "dom%d: pirq %d or irq %d already mapped (%d,%d)\n",
> > > d->domain_id, pirq, irq, old_pirq, old_irq);
> > > return 0;
> > > }
> > >
> > > Why do we return 0 instead of -EEXIST? Since the pirq is not updated, the
> > > caller doesn't know that pirq won't fire - only old_pirq. For
> > > allocate_and_map_gsi_pirq(), the new pirq is still returned to the caller.
> > > I would expect old_pirq to be returned so the caller knows what to use. Am
> > > I missing something?
> >
> > Looking at bfc341a65cfb2 it seems like this might have been an attempt
> > to keep the previous logic in ioapic_guest_write() that didn't return
> > an error when attempting to add/move an in use IRQ, while switching
> > ioapic_guest_write() to use map_domain_pirq()?
> >
> > The commit description is not very helpful sadly. I think the mention
> > of "And this patch also makes broken NetBSD dom0 work again." is
> > relevant. AFAICT NetBSD will do PHYSDEVOP_apic_read -> modify RTE (ie:
> > set mask bit for example) -> PHYSDEVOP_apic_write. However the
> > semantics of those hypercalls is not symmetric. PHYSDEVOP_apic_read
> > will return the vector used by Xen in the RTE, while
> > PHYSDEVOP_apic_write expects the vector field of the RTE to contain
> > the pIRQ. I think this is why map_domain_pirq() was adjusted in such
> > a weird way, to ignore requests with bogus pIRQs and still succeed, so
> > that PHYSDEVOP_apic_write would also succeed. Ideally the interface
> > should have been adjusted so that read/modify/write cycles using
> > PHYSDEVOP_apic_{read,write} would work as expected (iow:
> > PHYSDEVOP_apic_read should have returned the pIRQ in the vector
> > field).
> >
> > In the context of GSIs, I think we aim for Xen to always identity map
> > them (so IRQ == pIRQ), but there might be (or might have been)
> > hypercalls that could allow you to create non-identity mappings
> > between GSIs and pIRQs.
>
> To support non-PCI passthrough with Hyperlaunch, we added code to map a GSI
> to a vIOAPIC. It does not require identity mapping, and that works. It was
> while testing conditions that I expected to fail that I found the behavior.
>
> First map:
> machine A -> guest B
> Then map:
> machine A -> guest C "success" from the return 0
>
> > Explicitly looking at allocate_and_map_gsi_pirq() do you know what
> > causes the domain_irq_to_pirq() in allocate_pirq() to not return the
> > already allocated pIRQ that matches the passed IRQ?
>
> Well, it's PVH and I'm making up a "PIRQ" for the vIOAPIC.
Yeah, the vIO-APIC auto-map interface in vioapic_hwdom_map_gsi() for
PVH hwdom does use identity mappings between GSIs and pIRQs, but if
you use the side-band physdev interface you can certainly create
non-identity mappings between GSIs and pIRQs. That was introduced as
part of the PCI-passthrough work for PVH dom0 IIRC.
In fact what we do in vioapic_hwdom_map_gsi() might be dangerous now
that we allow a PVH dom0 to allocate and map GSIs using hypercalls
also. Using the hypercall interface a domain could introduce
non-identity GSI relations, which would then cause
vioapic_hwdom_map_gsi() to fail. It might be best to adjust the pirq
hint to be -1 in vioapic_hwdom_map_gsi() instead of gsi, and give up
on identity mappings GSIs to pIRQs on PVH hwdom from the vIO-APIC.
> > Overall we should likely adjust map_domain_pirq() to return -EEIXST,
> > and then fix ioapic_guest_write() to shallow such error so we can keep
> > the current behavior for that specific interface.
> Having been focused on PVH, I didn't look much at the PV behavior. But it
> was still surprising to see the "no-op" success.
Indeed, I think we want to contain that behavior to
ioapic_guest_write() exclusively. AFAICT the success is an unintended
effect of bfc341a65cfb2, which should have been limited to
ioapic_guest_write() exclusively.
Regards, Roger.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-05-15 8:35 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-14 1:18 map_domain_pirq(): pirq already mapped? Jason Andryuk
2026-05-14 8:26 ` Roger Pau Monné
2026-05-15 1:01 ` Jason Andryuk
2026-05-15 8:35 ` Roger Pau Monné
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.