From 520c7a309c64fd82a5e36821be2a89d040fef21c Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 5 Nov 2008 14:45:34 +0000 Subject: [PATCH] linux: prevent invalid or unsupportable PIRQs from being used By keeping the respective irq_desc[] entries pointing to no_irq_type, setup_irq() (and thus request_irq()) will fail for such IRQs. This matches native behavior, which also only installs ioapic_*_type out of ioapic_register_intr(). At the same time, make assign_irq_vector() fail not only when Xen doesn't support the PIRQ, but also if the IRQ requested doesn't fall in the kernel's PIRQ space. Signed-off-by: Jan Beulich --- arch/i386/kernel/io_apic-xen.c | 3 + arch/x86_64/kernel/io_apic-xen.c | 3 + drivers/xen/core/evtchn.c | 135 +++++++++++++++---------------- 3 files changed, 72 insertions(+), 69 deletions(-) diff --git a/arch/i386/kernel/io_apic-xen.c b/arch/i386/kernel/io_apic-xen.c index 68fb47aa..10f642a9 100644 --- a/arch/i386/kernel/io_apic-xen.c +++ b/arch/i386/kernel/io_apic-xen.c @@ -1216,6 +1216,9 @@ int assign_irq_vector(int irq) BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); + if (irq < PIRQ_BASE || irq - PIRQ_BASE > NR_PIRQS) + return -EINVAL; + spin_lock_irqsave(&vector_lock, flags); if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { diff --git a/arch/x86_64/kernel/io_apic-xen.c b/arch/x86_64/kernel/io_apic-xen.c index d70dd483..3ebaee64 100644 --- a/arch/x86_64/kernel/io_apic-xen.c +++ b/arch/x86_64/kernel/io_apic-xen.c @@ -895,6 +895,9 @@ int assign_irq_vector(int irq) BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); + if (irq < PIRQ_BASE || irq - PIRQ_BASE > NR_PIRQS) + return -EINVAL; + spin_lock_irqsave(&vector_lock, flags); if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { diff --git a/drivers/xen/core/evtchn.c b/drivers/xen/core/evtchn.c index 138ee73d..8a24e335 100644 --- a/drivers/xen/core/evtchn.c +++ b/drivers/xen/core/evtchn.c @@ -756,71 +756,6 @@ static struct hw_interrupt_type dynirq_type = { .retrigger = resend_irq_on_evtchn, }; -void evtchn_register_pirq(int irq) -{ - struct irq_desc *desc; - unsigned long flags; - - irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, 0); - - /* Cannot call set_irq_probe(), as that's marked __init. */ - desc = irq_desc + irq; - spin_lock_irqsave(&desc->lock, flags); - desc->status &= ~IRQ_NOPROBE; - spin_unlock_irqrestore(&desc->lock, flags); -} - -#if defined(CONFIG_X86_IO_APIC) -#define identity_mapped_irq(irq) (!IO_APIC_IRQ((irq) - PIRQ_BASE)) -#elif defined(CONFIG_X86) -#define identity_mapped_irq(irq) (((irq) - PIRQ_BASE) < 16) -#else -#define identity_mapped_irq(irq) (1) -#endif - -int evtchn_map_pirq(int irq, int xen_pirq) -{ - if (irq < 0) { - static DEFINE_SPINLOCK(irq_alloc_lock); - - irq = PIRQ_BASE + NR_PIRQS - 1; - spin_lock(&irq_alloc_lock); - do { - if (identity_mapped_irq(irq)) - continue; - if (!index_from_irq(irq)) { - BUG_ON(type_from_irq(irq) != IRQT_UNBOUND); - irq_info[irq] = mk_irq_info(IRQT_PIRQ, - xen_pirq, 0); - break; - } - } while (--irq >= PIRQ_BASE); - spin_unlock(&irq_alloc_lock); - if (irq < PIRQ_BASE) - return -ENOSPC; - } else if (!xen_pirq) { - if (unlikely(type_from_irq(irq) != IRQT_PIRQ)) - return -EINVAL; - irq_info[irq] = IRQ_UNBOUND; - return 0; - } else if (type_from_irq(irq) != IRQT_PIRQ - || index_from_irq(irq) != xen_pirq) { - printk(KERN_ERR "IRQ#%d is already mapped to %d:%u - " - "cannot map to PIRQ#%u\n", - irq, type_from_irq(irq), index_from_irq(irq), xen_pirq); - return -EINVAL; - } - return index_from_irq(irq) ? irq : -EINVAL; -} - -int evtchn_get_xen_pirq(int irq) -{ - if (identity_mapped_irq(irq)) - return irq; - BUG_ON(type_from_irq(irq) != IRQT_PIRQ); - return index_from_irq(irq); -} - static inline void pirq_unmask_notify(int irq) { struct physdev_eoi eoi = { .irq = evtchn_get_xen_pirq(irq) }; @@ -1098,6 +1033,68 @@ void irq_resume(void) } +#if defined(CONFIG_X86_IO_APIC) +#define identity_mapped_irq(irq) (!IO_APIC_IRQ((irq) - PIRQ_BASE)) +#elif defined(CONFIG_X86) +#define identity_mapped_irq(irq) (((irq) - PIRQ_BASE) < 16) +#else +#define identity_mapped_irq(irq) (1) +#endif + +void evtchn_register_pirq(int irq) +{ + BUG_ON(irq < PIRQ_BASE || irq - PIRQ_BASE > NR_PIRQS); + if (identity_mapped_irq(irq)) + return; + irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, 0); + set_irq_chip_and_handler_name(irq, &pirq_chip, handle_level_irq, "level"); +} + +int evtchn_map_pirq(int irq, int xen_pirq) +{ + if (irq < 0) { + static DEFINE_SPINLOCK(irq_alloc_lock); + + irq = PIRQ_BASE + NR_PIRQS - 1; + spin_lock(&irq_alloc_lock); + do { + if (identity_mapped_irq(irq)) + continue; + if (!index_from_irq(irq)) { + BUG_ON(type_from_irq(irq) != IRQT_UNBOUND); + irq_info[irq] = mk_irq_info(IRQT_PIRQ, + xen_pirq, 0); + break; + } + } while (--irq >= PIRQ_BASE); + spin_unlock(&irq_alloc_lock); + if (irq < PIRQ_BASE) + return -ENOSPC; + irq_desc[irq].chip = &pirq_type; + } else if (!xen_pirq) { + if (unlikely(type_from_irq(irq) != IRQT_PIRQ)) + return -EINVAL; + irq_desc[irq].chip = &no_irq_type; + irq_info[irq] = IRQ_UNBOUND; + return 0; + } else if (type_from_irq(irq) != IRQT_PIRQ + || index_from_irq(irq) != xen_pirq) { + printk(KERN_ERR "IRQ#%d is already mapped to %d:%u - " + "cannot map to PIRQ#%u\n", + irq, type_from_irq(irq), index_from_irq(irq), xen_pirq); + return -EINVAL; + } + return index_from_irq(irq) ? irq : -EINVAL; +} + +int evtchn_get_xen_pirq(int irq) +{ + if (identity_mapped_irq(irq)) + return irq; + BUG_ON(type_from_irq(irq) != IRQT_PIRQ); + return index_from_irq(irq); +} + void __init xen_init_IRQ(void) { unsigned int i; @@ -1126,16 +1123,16 @@ void __init xen_init_IRQ(void) for (i = PIRQ_BASE; i < (PIRQ_BASE + NR_PIRQS); i++) { irq_bindcount[i] = 1; + if (!identity_mapped_irq(i)) + continue; + #ifdef RTC_IRQ /* If not domain 0, force our RTC driver to fail its probe. */ - if (identity_mapped_irq(i) && ((i - PIRQ_BASE) == RTC_IRQ) - && !is_initial_xendomain()) + if (i - PIRQ_BASE == RTC_IRQ && !is_initial_xendomain()) continue; #endif irq_desc[i].status = IRQ_DISABLED; - if (!identity_mapped_irq(i)) - irq_desc[i].status |= IRQ_NOPROBE; irq_desc[i].action = NULL; irq_desc[i].depth = 1; irq_desc[i].chip = &pirq_type; -- 2.39.5