cortex-m/doirq: do not update the CURRENT_REGS on nested interrupt handling

current implementation incorrectly update CURRENT_REGS to interrupt context if
trigger nested interrupt, (e.g, hard fault occurs during interrupt handling)
this would ambiguous for programs using CURRENT_REGS, this patch will prohibit
the update of CURRENT_REGS on nested interrupt handling

Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an 2022-01-27 13:27:27 +08:00 committed by Xiang Xiao
parent d8c2610157
commit 7d8c2c1ad6
3 changed files with 42 additions and 58 deletions

View File

@ -35,22 +35,6 @@
#include "arm_arch.h"
#include "arm_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
@ -61,22 +45,22 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
#ifdef CONFIG_SUPPRESS_INTERRUPTS
PANIC();
#else
uint32_t *savestate;
/* Nested interrupts are not supported in this implementation. If you
* want to implement nested interrupts, you would have to (1) change the
* way that CURRENT_REGS is handled and (2) the design associated with
* CONFIG_ARCH_INTERRUPTSTACK. The savestate variable will not work for
* that purpose as implemented here because only the outermost nested
* interrupt can result in a context switch (it can probably be deleted).
* CONFIG_ARCH_INTERRUPTSTACK.
*/
/* Current regs non-zero indicates that we are processing an interrupt;
* CURRENT_REGS is also used to manage interrupt level context switches.
*/
savestate = (uint32_t *)CURRENT_REGS;
CURRENT_REGS = regs;
if (CURRENT_REGS == NULL)
{
CURRENT_REGS = regs;
regs = NULL;
}
/* Acknowledge the interrupt */
@ -84,7 +68,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
/* Deliver the IRQ */
irq_dispatch(irq, regs);
irq_dispatch(irq, (uint32_t *)CURRENT_REGS);
/* If a context switch occurred while processing the interrupt then
* CURRENT_REGS may have change value. If we return any value different
@ -92,15 +76,15 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
* switch occurred during interrupt processing.
*/
regs = (uint32_t *)CURRENT_REGS;
if (regs == NULL)
{
/* Update the return regs and restore the CURRENT_REGS to NULL. */
/* Restore the previous value of CURRENT_REGS. NULL would indicate that
* we are no longer in an interrupt handler. It will be non-NULL if we
* are returning from a nested interrupt.
*/
CURRENT_REGS = savestate;
regs = (uint32_t *)CURRENT_REGS;
CURRENT_REGS = NULL;
}
#endif
board_autoled_off(LED_INIRQ);
return regs;
}

View File

@ -45,22 +45,22 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
#ifdef CONFIG_SUPPRESS_INTERRUPTS
PANIC();
#else
uint32_t *savestate;
/* Nested interrupts are not supported in this implementation. If you
* want to implement nested interrupts, you would have to (1) change the
* way that CURRENT_REGS is handled and (2) the design associated with
* CONFIG_ARCH_INTERRUPTSTACK. The savestate variable will not work for
* that purpose as implemented here because only the outermost nested
* interrupt can result in a context switch.
* CONFIG_ARCH_INTERRUPTSTACK.
*/
/* Current regs non-zero indicates that we are processing an interrupt;
* CURRENT_REGS is also used to manage interrupt level context switches.
*/
savestate = (uint32_t *)CURRENT_REGS;
CURRENT_REGS = regs;
if (CURRENT_REGS == NULL)
{
CURRENT_REGS = regs;
regs = NULL;
}
/* Acknowledge the interrupt */
@ -68,7 +68,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
/* Deliver the IRQ */
irq_dispatch(irq, regs);
irq_dispatch(irq, (uint32_t *)CURRENT_REGS);
/* If a context switch occurred while processing the interrupt then
* CURRENT_REGS may have change value. If we return any value different
@ -76,15 +76,15 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
* switch occurred during interrupt processing.
*/
regs = (uint32_t *)CURRENT_REGS;
if (regs == NULL)
{
/* Update the return regs and restore the CURRENT_REGS to NULL. */
/* Restore the previous value of CURRENT_REGS. NULL would indicate that
* we are no longer in an interrupt handler. It will be non-NULL if we
* are returning from a nested interrupt.
*/
CURRENT_REGS = savestate;
regs = (uint32_t *)CURRENT_REGS;
CURRENT_REGS = NULL;
}
#endif
board_autoled_off(LED_INIRQ);
return regs;
}

View File

@ -45,22 +45,22 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
#ifdef CONFIG_SUPPRESS_INTERRUPTS
PANIC();
#else
uint32_t *savestate;
/* Nested interrupts are not supported in this implementation. If you
* want to implement nested interrupts, you would have to (1) change the
* way that CURRENT_REGS is handled and (2) the design associated with
* CONFIG_ARCH_INTERRUPTSTACK. The savestate variable will not work for
* that purpose as implemented here because only the outermost nested
* interrupt can result in a context switch.
* CONFIG_ARCH_INTERRUPTSTACK.
*/
/* Current regs non-zero indicates that we are processing an interrupt;
* CURRENT_REGS is also used to manage interrupt level context switches.
*/
savestate = (uint32_t *)CURRENT_REGS;
CURRENT_REGS = regs;
if (CURRENT_REGS == NULL)
{
CURRENT_REGS = regs;
regs = NULL;
}
/* Acknowledge the interrupt */
@ -68,7 +68,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
/* Deliver the IRQ */
irq_dispatch(irq, regs);
irq_dispatch(irq, (uint32_t *)CURRENT_REGS);
/* If a context switch occurred while processing the interrupt then
* CURRENT_REGS may have change value. If we return any value different
@ -76,15 +76,15 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
* switch occurred during interrupt processing.
*/
regs = (uint32_t *)CURRENT_REGS;
if (regs == NULL)
{
/* Update the return regs and restore the CURRENT_REGS to NULL. */
/* Restore the previous value of CURRENT_REGS. NULL would indicate that
* we are no longer in an interrupt handler. It will be non-NULL if we
* are returning from a nested interrupt.
*/
CURRENT_REGS = savestate;
regs = (uint32_t *)CURRENT_REGS;
CURRENT_REGS = NULL;
}
#endif
board_autoled_off(LED_INIRQ);
return regs;
}