|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v4 21/25] xen/riscv: implement IRQ routing for device passthrough
On 6/29/26 5:55 PM, Jan Beulich wrote: On 26.06.2026 17:46, Oleksii Kurochko wrote:dom0less device passthrough requires granting guest domains access to device interrupts. Introduce map_device_irqs_to_domain() to enumerate a DT node's interrupt properties, skipping those not owned by the primary interrupt controller (as at the moment I haven't seen usages of it), and map_irq_to_domain() to grant domain access and configure Xen's interrupt descriptor accordingly. Sharing IRQ between domains is rejected. Both map_irq_to_domain() and map_device_irqs_to_domain() are marked __overlay_init, mirroring Arm: without CONFIG_OVERLAY_DTB this expands to __init, so the functions are init-only and need no XSM check; with CONFIG_OVERLAY_DTB they become runtime-callable, but the only runtime entry point is dt_overlay_domctl(), which performs the XSM checks at the domctl layer. RISC-V does not wire up DT overlay yet, so today these are strictly __init; if/when overlay support is added, the domctl-level XSM gating must be added together with it, as on Arm. route_irq_to_guest() and release_irq() manage irq_desc ownership for guest-assigned interrupts. Each assignment carries a small irq_guest structure as irqaction::dev_id, recording the owning domain and virtual IRQ number which is 1:1 mapped to physical IRQ number. A per-domain vIRQ allocation bitmap (used_irqs in struct vintc), managed by vintc_reserve_virq(), prevents the same vIRQ being claimed twice. Host and guest interrupts may differ in some operations (EOI timing in particular, possibly others): a host IRQ is completed once Xen's handler runs, whereas a passthrough IRQ must defer the physical completion until the guest issues its own EOI, otherwise a still-asserted level line would immediately retrigger and storm. This affects only the .end callback; the rest of hw_interrupt_type is shared, hence the separate host and guest hw_interrupt_type instances. With APLIC+IMSIC, guest interrupts are delivered directly by hardware through the IMSIC, bypassing do_IRQ(). The _IRQ_GUEST branch in do_IRQ() is therefore left as BUG() until a platform without direct IMSIC delivery is encountered.And this is secure, i.e. one guest (by mishandling things, e.g. simply never claiming / servicing an interrupt) cannot affect another guest? It will be just affect this specific interrupt which isn't claimed/serviced.
I would be okay to have a format string a little bit long. I would change that line to (if you are okay with that):
...("irq %u not connected to primary controller. Connected to %s\n",
i, dt_node_full_name(rirq.controller));
I will reformat that in the following way:
d->arch.vintc->used_irqs =
xvzalloc_array(unsigned long,
BITS_TO_LONGS(d->arch.vintc->nr_virqs));
Right, it is an issue: d->arch.vintc is being NULLed inside domain_vaplic_deinit(), which are called from domain_vintc_deinit(), so XVFREE(d->arch.vintc->used_irqs) must be moved to just after the for() loop (before the switch). As for d->arch.vintc itself, it should only be NULLed and not freed, since it is a pointer to &vaplic->vintc which is embedded in the vaplic struct and not separately allocated. --- a/xen/arch/riscv/irq.c +++ b/xen/arch/riscv/irq.c @@ -12,11 +12,20 @@ #include <xen/errno.h> #include <xen/init.h> #include <xen/irq.h> +#include <xen/sched.h> #include <xen/spinlock.h> +#include <xen/xvmalloc.h>#include <asm/hardirq.h>#include <asm/intc.h>+/* Describe an IRQ assigned to a guest */ I will rephrase it for clarity: /* * With APLIC + IMSIC, guest interrupts bypass Xen and are delivered * directly to the guest. Without IMSIC, interrupts would be trapped * by Xen and would need injecting into the guest here. */ It looks more clearer to me.
Considering that I used irq_get_domain() once at all (even in downstream) I will drop that. For both functions: "inline" generally wants limiting to header files. Regarding inline I think that I don't understand, it isn't in the header file as irq_get_guest_info() is used only in this file. Do I understand you correctly and it is needed just to drop "inline" for irq_get_guest_info()?
Right, it is needed to add:
if ( d->is_dying )
return -EINVAL;
at the top of route_irq_to_guest().
+ /* + * Clear _IRQ_GUEST while still holding the lock so that a concurrent + * release_guest_irq() for the same IRQ observes it and bails out, rather + * than capturing the same 'info' and double-freeing it below. + */ + clear_bit(_IRQ_GUEST, &desc->status);You use __set_bit() / __clear_bit() elsewhere - why not here? As it is under spinlock it could __clear_bit here. + spin_unlock_irqrestore(&desc->lock, flags); + + release_irq(desc->irq, info); + xvfree(info);If, in release_irq(), action isn't freed, it's ->dev_id field will now have a dangling pointer. (I think I did point this out before.) It should freed in release_irq() as route_irq_to_guest() always set action->free_on_release = true; Thanks. ~ Oleksii
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |