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:
Julien Grall authored and Ian Campbell committed 2015-04-02 10:42:35 +01:00
1 parent 86ce68f7bb
commit 3998a3ce50
3 files changed
+40 -14

No files matched your search

+27 -8
View File
@@ -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
View File
@@ -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;
+3 -4
View File
@@ -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);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.