Skip to content

Commit

Permalink
arch/arm/src/armv7-m: Add support of nested interrupts
Browse files Browse the repository at this point in the history
This patch adds the support of nested interrupts for armv7-m
architecture.

Signed-off-by: Drashti Parikh <[email protected]>
  • Loading branch information
drashti304 committed May 23, 2019
1 parent ebc38e5 commit a8ae569
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 15 deletions.
15 changes: 15 additions & 0 deletions os/arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ config ARCH_ARM
select ARCH_HAVE_VFORK
select ARCH_HAVE_STACKCHECK
select ARCH_HAVE_CUSTOMOPT
select ARCH_HAVE_NESTED_INTERRUPT
---help---
The ARM architectures

Expand Down Expand Up @@ -571,6 +572,20 @@ config ARCH_INTERRUPTSTACK
defined to be zero), the user task stacks will be used during interrupt
handling.

config ARCH_HAVE_NESTED_INTERRUPT
bool
default n

if ARCH_INTERRUPTSTACK > 7
config ARCH_NESTED_INTERRUPT
bool "Nested interrupt support"
depends on ARCH_HAVE_NESTED_INTERRUPT
default n
---help---
Enables the nested interrupt support. If defined, higher priority interrupt
can pre-empt the lower priority interrupt.
endif

config ARCH_HAVE_HIPRI_INTERRUPT
bool
default n
Expand Down
57 changes: 50 additions & 7 deletions os/arch/arm/src/armv7-m/up_doirq.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@
/****************************************************************************
* Public Data
****************************************************************************/

#if CONFIG_ARCH_INTERRUPTSTACK > 7
extern uint32_t g_nestlevel; /* Initial top of interrupt stack */
#endif
/****************************************************************************
* Private Data
****************************************************************************/
Expand All @@ -88,10 +90,31 @@

uint32_t *up_doirq(int irq, uint32_t *regs)
{
#if CONFIG_ARCH_INTERRUPTSTACK > 7
irqstate_t flags;
#endif
board_led_on(LED_INIRQ);
#ifdef CONFIG_SUPPRESS_INTERRUPTS
PANIC();
#else

#if CONFIG_ARCH_INTERRUPTSTACK > 7
/* Current regs non-zero indicates that we are processing an interrupt;
* regs holds the state of the interrupted logic; current_regs holds the
* state of the interrupted user task. current_regs should, therefor,
* only be modified for outermost interrupt handler (when g_nestlevel == 0)
*/

flags = irqsave();

if (g_nestlevel == 0) {
current_regs = regs;
}

g_nestlevel++;

irqrestore(flags);
#else
uint32_t *savestate;

/* Nested interrupts are not supported in this implementation. If you want
Expand All @@ -101,22 +124,41 @@ uint32_t *up_doirq(int irq, uint32_t *regs)
* that purpose as implemented here because only the outermost nested
* interrupt can result in a context switch (it can probably be deleted).
*/

/* 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;

/* Acknowledge the interrupt */

up_ack_irq(irq);
#endif

/* Deliver the IRQ */

irq_dispatch(irq, regs);

#if CONFIG_ARCH_INTERRUPTSTACK > 7
/* Context switches are indicated by the returned value of this function.
* If a context switch occurred while processing the interrupt then
* current_regs may have change value. If we return any value different
* from the input regs, then the lower level will know that a context
* switch occurred during interrupt processing. Context switching should
* only be performed when the outermost interrupt handler returns.
*/

flags = irqsave();

g_nestlevel--;

if (g_nestlevel == 0) {
regs = (uint32_t*)current_regs;
current_regs = NULL;
}

/* Note that interrupts are left disabled. This needed if context switch
* will be performed. But, any case, the correct interrupt state should
* be restored when returning from the interrupt.
*/

#else
/* If a context switch occurred while processing the interrupt then
* current_regs may have change value. If we return any value different
* from the input regs, then the lower level will know that a context
Expand All @@ -131,6 +173,7 @@ uint32_t *up_doirq(int irq, uint32_t *regs)
*/

current_regs = savestate;
#endif
#endif
board_led_off(LED_INIRQ);
return regs;
Expand Down
26 changes: 18 additions & 8 deletions os/arch/arm/src/armv7-m/up_lazyexception.S
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,15 @@ exception_common:
stmdb sp!, {r2-r11} /* Save the remaining registers plus the SP value */
#endif

#ifndef CONFIG_ARCH_HIPRI_INTERRUPT
#if !defined(CONFIG_ARCH_HIPRI_INTERRUPT) && !defined(CONFIG_ARCH_NESTED_INTERRUPT)

/* Disable interrupts, select the stack to use for interrupt handling
* and call up_doirq to handle the interrupt
*/

cpsid i /* Disable further interrupts */

#else
#elif !defined(CONFIG_ARCH_NESTED_INTERRUPT)
/* Set the BASEPRI register so that further normal interrupts will be
* masked. Nested, high priority may still occur, however.
*
Expand Down Expand Up @@ -240,13 +241,17 @@ exception_common:
mov r4, sp

#if CONFIG_ARCH_INTERRUPTSTACK > 7
/* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will set the MSP to use
* a special special interrupt stack pointer. The way that this is done
* here prohibits nested interrupts without some additional logic!
*/

setintstack r2, r3
/* If g_nestlevel is zero then behave as normal, switching from the user
* to the interrupt stack; if g_nestlevel is greater than zero, then do
* not switch stacks. In this latter case, we are already using the interrupt stack */

ldr r5, =g_nestlevel
ldr r6, [r5]
cmp r6, #0
bne 9f
ldr sp, =g_intstackbase
9:
#else
/* Otherwise, we will re-use the interrupted thread's stack. That may
* mean using either MSP or PSP stack for interrupt level processing (in
Expand Down Expand Up @@ -370,7 +375,7 @@ exception_common:

#ifdef CONFIG_ARMV7M_USEBASEPRI
msr basepri, r3 /* Restore interrupts priority masking */
#ifndef CONFIG_ARCH_HIPRI_INTERRUPT
#if !defined(CONFIG_ARCH_HIPRI_INTERRUPT) && !defined(CONFIG_ARCH_NESTED_INTERRUPT)
cpsie i /* Re-enable interrupts */
#endif

Expand All @@ -397,11 +402,16 @@ exception_common:
.bss
.global g_intstackalloc
.global g_intstackbase
.global g_nestlevel
.align 8
g_intstackalloc:
.skip ((CONFIG_ARCH_INTERRUPTSTACK + 4) & ~7)
g_intstackbase:
.size g_intstackalloc, .-g_intstackalloc
.skip 4
g_nestlevel:
.skip 4
.size g_nestlevel, 4
#endif

.end

0 comments on commit a8ae569

Please sign in to comment.