arm64: irq: allow FIQs to be handled
On contemporary platforms we don't use FIQ, and treat any stray FIQ as a fatal event. However, some platforms have an interrupt controller wired to FIQ, and need to handle FIQ as part of regular operation. So that we can support both cases dynamically, this patch updates the FIQ exception handling code to operate the same way as the IRQ handling code, with its own handle_arch_fiq handler. Where a root FIQ handler is not registered, an unexpected FIQ exception will trigger the default FIQ handler, which will panic() as today. Where a root FIQ handler is registered, handling of the FIQ is deferred to that handler. As el0_fiq_invalid_compat is supplanted by el0_fiq, the former is removed. For !CONFIG_COMPAT builds we never expect to take an exception from AArch32 EL0, so we keep the common el0_fiq_invalid handler. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Tested-by: Hector Martin <marcan@marcan.st> Cc: James Morse <james.morse@arm.com> Cc: Marc Zyngier <maz@kernel.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Will Deacon <will@kernel.org> Acked-by: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20210315115629.57191-7-mark.rutland@arm.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
Родитель
f0098155d3
Коммит
3889ba7010
|
@ -10,6 +10,7 @@ struct pt_regs;
|
|||
|
||||
int set_handle_irq(void (*handle_irq)(struct pt_regs *));
|
||||
#define set_handle_irq set_handle_irq
|
||||
int set_handle_fiq(void (*handle_fiq)(struct pt_regs *));
|
||||
|
||||
static inline int nr_legacy_irqs(void)
|
||||
{
|
||||
|
|
|
@ -588,18 +588,18 @@ SYM_CODE_START(vectors)
|
|||
|
||||
kernel_ventry 1, sync // Synchronous EL1h
|
||||
kernel_ventry 1, irq // IRQ EL1h
|
||||
kernel_ventry 1, fiq_invalid // FIQ EL1h
|
||||
kernel_ventry 1, fiq // FIQ EL1h
|
||||
kernel_ventry 1, error // Error EL1h
|
||||
|
||||
kernel_ventry 0, sync // Synchronous 64-bit EL0
|
||||
kernel_ventry 0, irq // IRQ 64-bit EL0
|
||||
kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0
|
||||
kernel_ventry 0, fiq // FIQ 64-bit EL0
|
||||
kernel_ventry 0, error // Error 64-bit EL0
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0
|
||||
kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0
|
||||
kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0
|
||||
kernel_ventry 0, fiq_compat, 32 // FIQ 32-bit EL0
|
||||
kernel_ventry 0, error_compat, 32 // Error 32-bit EL0
|
||||
#else
|
||||
kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0
|
||||
|
@ -665,12 +665,6 @@ SYM_CODE_START_LOCAL(el0_error_invalid)
|
|||
inv_entry 0, BAD_ERROR
|
||||
SYM_CODE_END(el0_error_invalid)
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
SYM_CODE_START_LOCAL(el0_fiq_invalid_compat)
|
||||
inv_entry 0, BAD_FIQ, 32
|
||||
SYM_CODE_END(el0_fiq_invalid_compat)
|
||||
#endif
|
||||
|
||||
SYM_CODE_START_LOCAL(el1_sync_invalid)
|
||||
inv_entry 1, BAD_SYNC
|
||||
SYM_CODE_END(el1_sync_invalid)
|
||||
|
@ -705,6 +699,12 @@ SYM_CODE_START_LOCAL_NOALIGN(el1_irq)
|
|||
kernel_exit 1
|
||||
SYM_CODE_END(el1_irq)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(el1_fiq)
|
||||
kernel_entry 1
|
||||
el1_interrupt_handler handle_arch_fiq
|
||||
kernel_exit 1
|
||||
SYM_CODE_END(el1_fiq)
|
||||
|
||||
/*
|
||||
* EL0 mode handlers.
|
||||
*/
|
||||
|
@ -731,6 +731,11 @@ SYM_CODE_START_LOCAL_NOALIGN(el0_irq_compat)
|
|||
b el0_irq_naked
|
||||
SYM_CODE_END(el0_irq_compat)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(el0_fiq_compat)
|
||||
kernel_entry 0, 32
|
||||
b el0_fiq_naked
|
||||
SYM_CODE_END(el0_fiq_compat)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(el0_error_compat)
|
||||
kernel_entry 0, 32
|
||||
b el0_error_naked
|
||||
|
@ -745,6 +750,13 @@ el0_irq_naked:
|
|||
b ret_to_user
|
||||
SYM_CODE_END(el0_irq)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(el0_fiq)
|
||||
kernel_entry 0
|
||||
el0_fiq_naked:
|
||||
el0_interrupt_handler handle_arch_fiq
|
||||
b ret_to_user
|
||||
SYM_CODE_END(el0_fiq)
|
||||
|
||||
SYM_CODE_START_LOCAL(el1_error)
|
||||
kernel_entry 1
|
||||
mrs x1, esr_el1
|
||||
|
|
|
@ -76,7 +76,13 @@ static void default_handle_irq(struct pt_regs *regs)
|
|||
panic("IRQ taken without a root IRQ handler\n");
|
||||
}
|
||||
|
||||
static void default_handle_fiq(struct pt_regs *regs)
|
||||
{
|
||||
panic("FIQ taken without a root FIQ handler\n");
|
||||
}
|
||||
|
||||
void (*handle_arch_irq)(struct pt_regs *) __ro_after_init = default_handle_irq;
|
||||
void (*handle_arch_fiq)(struct pt_regs *) __ro_after_init = default_handle_fiq;
|
||||
|
||||
int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
|
||||
{
|
||||
|
@ -88,6 +94,16 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init set_handle_fiq(void (*handle_fiq)(struct pt_regs *))
|
||||
{
|
||||
if (handle_arch_fiq != default_handle_fiq)
|
||||
return -EBUSY;
|
||||
|
||||
handle_arch_fiq = handle_fiq;
|
||||
pr_info("Root FIQ handler: %ps\n", handle_fiq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init init_IRQ(void)
|
||||
{
|
||||
init_irq_stacks();
|
||||
|
|
Загрузка…
Ссылка в новой задаче