mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
xen/arm: gic: Add sanity checks gic_route_irq_to_guest
With the addition of interrupt assignment to guest, we need to make sure
the guest can't blow up the interrupt management in Xen.
Before associating the IRQ to a vIRQ we need to make sure:
- the vIRQ is not already associated to another IRQ
- the guest didn't enable the vIRQ
Signed-off-by: Julien Grall <julien.grall@linaro.org>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
1 parent
86ce68f7bb
commit
3998a3ce50
3 files changed
+40
-14
No files matched your search
+27
-8
@@ -126,22 +126,41 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
|
||||
/* Program the GIC to route an interrupt to a guest
|
||||
* - desc.lock must be held
|
||||
*/
|
||||
void gic_route_irq_to_guest(struct domain *d, unsigned int virq,
|
||||
struct irq_desc *desc,
|
||||
const cpumask_t *cpu_mask, unsigned int priority)
|
||||
int gic_route_irq_to_guest(struct domain *d, unsigned int virq,
|
||||
struct irq_desc *desc, unsigned int priority)
|
||||
{
|
||||
struct pending_irq *p;
|
||||
unsigned long flags;
|
||||
/* Use vcpu0 to retrieve the pending_irq struct. Given that we only
|
||||
* route SPIs to guests, it doesn't make any difference. */
|
||||
struct vcpu *v_target = vgic_get_target_vcpu(d->vcpu[0], virq);
|
||||
struct vgic_irq_rank *rank = vgic_rank_irq(v_target, virq);
|
||||
struct pending_irq *p = irq_to_pending(v_target, virq);
|
||||
int res = -EBUSY;
|
||||
|
||||
ASSERT(spin_is_locked(&desc->lock));
|
||||
/* Caller has already checked that the IRQ is an SPI */
|
||||
ASSERT(virq >= 32);
|
||||
ASSERT(virq < vgic_num_irqs(d));
|
||||
|
||||
vgic_lock_rank(v_target, rank, flags);
|
||||
|
||||
if ( p->desc ||
|
||||
/* The VIRQ should not be already enabled by the guest */
|
||||
test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) )
|
||||
goto out;
|
||||
|
||||
desc->handler = gic_hw_ops->gic_guest_irq_type;
|
||||
set_bit(_IRQ_GUEST, &desc->status);
|
||||
|
||||
gic_set_irq_properties(desc, cpumask_of(smp_processor_id()), GIC_PRI_IRQ);
|
||||
gic_set_irq_properties(desc, cpumask_of(v_target->processor), GIC_PRI_IRQ);
|
||||
|
||||
/* Use vcpu0 to retrieve the pending_irq struct. Given that we only
|
||||
* route SPIs to guests, it doesn't make any difference. */
|
||||
p = irq_to_pending(d->vcpu[0], virq);
|
||||
p->desc = desc;
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
vgic_unlock_rank(v_target, rank, flags);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
|
||||
|
||||
+10
-2
@@ -492,14 +492,22 @@ int route_irq_to_guest(struct domain *d, unsigned int virq,
|
||||
if ( retval )
|
||||
goto out;
|
||||
|
||||
gic_route_irq_to_guest(d, virq, desc, cpumask_of(smp_processor_id()),
|
||||
GIC_PRI_IRQ);
|
||||
retval = gic_route_irq_to_guest(d, virq, desc, GIC_PRI_IRQ);
|
||||
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
|
||||
if ( retval )
|
||||
{
|
||||
release_irq(desc->irq, info);
|
||||
goto free_info;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
xfree(action);
|
||||
free_info:
|
||||
xfree(info);
|
||||
|
||||
return retval;
|
||||
|
||||
@@ -216,10 +216,9 @@ extern enum gic_version gic_hw_version(void);
|
||||
/* Program the GIC to route an interrupt */
|
||||
extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
|
||||
unsigned int priority);
|
||||
extern void gic_route_irq_to_guest(struct domain *, unsigned int virq,
|
||||
struct irq_desc *desc,
|
||||
const cpumask_t *cpu_mask,
|
||||
unsigned int priority);
|
||||
extern int gic_route_irq_to_guest(struct domain *, unsigned int virq,
|
||||
struct irq_desc *desc,
|
||||
unsigned int priority);
|
||||
|
||||
extern void gic_inject(void);
|
||||
extern void gic_clear_pending_irqs(struct vcpu *v);
|
||||
|
||||