Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interrupt nesting #10057

Merged
merged 9 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
arch/armv7-m: Supports interrupt nesting
1、The process stack supports interrupt nesting, Execute in MSP;
2、The interrupt stack supports interrupt nesting;
   The thread mode use PSP, and the handle mode use MSP;
3、Adjust arm_doirq、exception_common implementation to meet interrupt nesting
4、Adjust the conditions for returning MSP and PSP;
5、remove setintstack,add arm_initialize_stack;

Signed-off-by: wangming9 <[email protected]>
  • Loading branch information
wangming9 committed Aug 3, 2023
commit 054d8f0108239f751bdaa82366a1bbdc3ef092bd
18 changes: 4 additions & 14 deletions arch/arm/src/armv7-m/arm_doirq.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <sched/sched.h>

#include "arm_internal.h"
#include "exc_return.h"

/****************************************************************************
* Public Functions
Expand All @@ -46,20 +47,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
PANIC();
#else

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

/* Current regs non-zero indicates that we are processing an interrupt;
* CURRENT_REGS is also used to manage interrupt level context switches.
*/

if (CURRENT_REGS == NULL)
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
{
CURRENT_REGS = regs;
regs = NULL;
}

/* Acknowledge the interrupt */
Expand All @@ -68,15 +58,15 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)

/* Deliver the IRQ */

irq_dispatch(irq, (uint32_t *)CURRENT_REGS);
irq_dispatch(irq, regs);

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

if (regs == NULL)
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
{
/* Restore the cpu lock */

Expand Down
56 changes: 18 additions & 38 deletions arch/arm/src/armv7-m/arm_exception.S
Original file line number Diff line number Diff line change
Expand Up @@ -92,25 +92,6 @@
.thumb
.file "arm_exception.S"

/****************************************************************************
* Macro Definitions
****************************************************************************/

/****************************************************************************
* Name: setintstack
*
* Description:
* Set the current stack pointer to the "top" the interrupt stack. Single CPU
* case. Must be provided by MCU-specific logic in the SMP case.
*
****************************************************************************/

#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7
.macro setintstack, tmp1, tmp2
ldr sp, =g_intstacktop
.endm
#endif

/****************************************************************************
* .text
****************************************************************************/
Expand Down Expand Up @@ -151,9 +132,14 @@ exception_common:
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */
beq 1f /* Branch if context already on the MSP */
mrs r1, psp /* R1=The process stack pointer (PSP) */
mov sp, r1 /* Set the MSP to the PSP */
b 2f
1:
mov r2, sp /* R2=Copy of the main/process stack pointer */
mrs r1, msp /* R1=The main stack pointer (MSP) */
sub r2, r1, #SW_XCPT_SIZE /* Reserved stack space */
msr msp, r2

2:
mov r2, r1 /* R2=Copy of the main/process stack pointer */
add r2, #HW_XCPT_SIZE /* R2=MSP/PSP before the interrupt was taken */
/* (ignoring the xPSR[9] alignment bit) */
#ifdef CONFIG_ARMV7M_USEBASEPRI
Expand All @@ -179,31 +165,22 @@ exception_common:

tst r14, #EXC_RETURN_STD_CONTEXT
ite eq
vstmdbeq sp!, {s16-s31} /* Save the non-volatile FP context */
subne sp, #(4*SW_FPU_REGS)
vstmdbeq r1!, {s16-s31} /* Save the non-volatile FP context */
subne r1, #(4*SW_FPU_REGS)
#endif

stmdb sp!, {r2-r12,r14} /* Save the remaining registers plus the SP/PRIMASK values */
stmdb r1!, {r2-r12,r14} /* Save the remaining registers plus the SP/PRIMASK values */

/* There are two arguments to arm_doirq:
*
* R0 = The IRQ number
* R1 = The top of the stack points to the saved state
*/

mov r1, 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 /* SP = IRQ stack top */
#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
* kernel mode).
#if CONFIG_ARCH_INTERRUPTSTACK < 7
/* If CONFIG_ARCH_INTERRUPTSTACK is not defined, we will re-use the
* interrupted thread's stack. That may mean using either MSP or PSP
* stack for interrupt level processing (in kernel mode).
*/

/* If the interrupt stack is disabled, reserve xcpcontext to ensure
Expand All @@ -217,9 +194,12 @@ exception_common:
* also the sp should be restore after arm_doirq()
*/

tst r14, #EXC_RETURN_THREAD_MODE /* Nonzero if context on thread mode */
beq 3f /* Branch if context already on the handle mode */
sub r2, r1, #XCPTCONTEXT_SIZE /* Reserve signal context */
bic r2, r2, #7 /* Get the stack pointer with 8-byte alignment */
mov sp, r2 /* Instantiate the aligned stack */
3:
#endif

bl arm_doirq /* R0=IRQ, R1=register save (msp) */
Expand All @@ -241,7 +221,7 @@ exception_common:
/* The EXC_RETURN value tells us whether we are returning on the MSP or PSP
*/

tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */
tst r14, #EXC_RETURN_PROCESS_STACK /* Nonzero if context on process stack */
ite eq /* Next two instructions conditional */
msreq msp, r0 /* R0=The main stack pointer */
msrne psp, r0 /* R0=The process stack pointer */
Expand Down
44 changes: 43 additions & 1 deletion arch/arm/src/armv7-m/arm_initialstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ void up_initial_state(struct tcb_s *tcb)
* mode before transferring control to the user task.
*/

xcp->regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
xcp->regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;

xcp->regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;

Expand All @@ -168,3 +168,45 @@ void up_initial_state(struct tcb_s *tcb)

#endif /* CONFIG_SUPPRESS_INTERRUPTS */
}

#if CONFIG_ARCH_INTERRUPTSTACK > 7
/****************************************************************************
* Name: arm_initialize_stack
*
* Description:
* If interrupt stack is defined, the PSP and MSP need to be reinitialized.
*
****************************************************************************/

noinline_function void arm_initialize_stack(void)
{
#ifdef CONFIG_SMP
uint32_t stack = (uint32_t)arm_intstack_top();
#else
uint32_t stack = (uint32_t)g_intstacktop;
#endif
uint32_t temp = 0;

__asm__ __volatile__
(

/* Initialize PSP */

"mov %1, sp\n"
"msr psp, %1\n"

/* Select PSP */

"mrs %1, CONTROL\n"
"orr %1, #2\n"
"msr CONTROL, %1\n"
"isb sy\n"

/* Initialize MSP */

"msr msp, %0\n"
:
: "r" (stack), "r" (temp)
: "memory");
}
#endif
12 changes: 6 additions & 6 deletions arch/arm/src/armv7-m/arm_schedulesigaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
CURRENT_REGS[REG_XPSR] = ARMV7M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED
CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR;
CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
CURRENT_REGS[REG_LR] = EXC_RETURN_THREAD;
CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_THREAD;
CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif
}
Expand Down Expand Up @@ -209,7 +209,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR;
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif
}
Expand Down Expand Up @@ -320,7 +320,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR;
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif
}
Expand Down Expand Up @@ -367,7 +367,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
CURRENT_REGS[REG_XPSR] = ARMV7M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED
CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR;
CURRENT_REGS[REG_LR] = EXC_RETURN_THREAD;
CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif
}
Expand Down Expand Up @@ -430,7 +430,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR;
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif
}
Expand Down
10 changes: 5 additions & 5 deletions arch/arm/src/armv7-m/arm_svcall.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/

regs[REG_PC] = (uint32_t)USERSPACE->task_startup & ~1;
regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;

/* Return unprivileged mode */

Expand Down Expand Up @@ -308,7 +308,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/

regs[REG_PC] = (uint32_t)regs[REG_R1] & ~1; /* startup */
regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;

/* Return unprivileged mode */

Expand Down Expand Up @@ -353,7 +353,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/

regs[REG_PC] = (uint32_t)USERSPACE->signal_handler & ~1;
regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;

/* Return unprivileged mode */

Expand Down Expand Up @@ -390,7 +390,7 @@ int arm_svcall(int irq, void *context, void *arg)
DEBUGASSERT(rtcb->xcp.sigreturn != 0);

regs[REG_PC] = rtcb->xcp.sigreturn & ~1;
regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;

/* Return privileged mode */

Expand Down Expand Up @@ -428,7 +428,7 @@ int arm_svcall(int irq, void *context, void *arg)
rtcb->xcp.nsyscalls = index + 1;

regs[REG_PC] = (uint32_t)dispatch_syscall & ~1;
regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;

/* Return privileged mode */

Expand Down
31 changes: 15 additions & 16 deletions arch/arm/src/armv7-m/exc_return.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,29 +77,28 @@

#define EXC_RETURN_HANDLER 0xfffffff1

/* EXC_RETURN_PRIVTHR: Return to privileged thread mode. Exception return
* gets state from the main stack. Execution uses MSP after return.
*/

#ifdef CONFIG_ARCH_FPU
# define EXC_RETURN_PRIVTHR (EXC_RETURN_BASE | EXC_RETURN_THREAD_MODE)
# define EXC_RETURN_FPU 0
#else
# define EXC_RETURN_PRIVTHR (EXC_RETURN_BASE | EXC_RETURN_STD_CONTEXT | \
EXC_RETURN_THREAD_MODE)
# define EXC_RETURN_FPU EXC_RETURN_STD_CONTEXT
#endif

/* EXC_RETURN_UNPRIVTHR: Return to unprivileged thread mode. Exception return
* gets state from the process stack. Execution uses PSP after return.
*/

#ifdef CONFIG_ARCH_FPU
# define EXC_RETURN_UNPRIVTHR (EXC_RETURN_BASE | EXC_RETURN_THREAD_MODE | \
EXC_RETURN_PROCESS_STACK)
#if CONFIG_ARCH_INTERRUPTSTACK > 7
# define EXC_RETURN_STACK EXC_RETURN_PROCESS_STACK
#else
# define EXC_RETURN_UNPRIVTHR (EXC_RETURN_BASE | EXC_RETURN_STD_CONTEXT | \
EXC_RETURN_THREAD_MODE | EXC_RETURN_PROCESS_STACK)
# define EXC_RETURN_STACK 0
#endif

/* EXC_RETURN_THREAD: Return to thread mode.
* If EXC_RETURN_STACK is 0, Return to thread mode.
* Execution uses MSP after return.
* If EXC_RETURN_STACK is EXC_RETURN_PROCESS_STACK, Return to
* thread mode. Execution uses PSP after return.
*/

#define EXC_RETURN_THREAD (EXC_RETURN_BASE | EXC_RETURN_FPU | \
EXC_RETURN_THREAD_MODE | EXC_RETURN_STACK)

/****************************************************************************
* Inline Functions
****************************************************************************/
Expand Down
6 changes: 6 additions & 0 deletions arch/arm/src/common/arm_initialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ static inline void arm_color_intstack(void)

void up_initialize(void)
{
#if CONFIG_ARCH_INTERRUPTSTACK > 7
/* Reinitializes the stack pointer */

arm_initialize_stack();
#endif

/* Colorize the interrupt stack */

arm_color_intstack();
Expand Down
4 changes: 4 additions & 0 deletions arch/arm/src/common/arm_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,10 @@ uintptr_t arm_intstack_alloc(void);
uintptr_t arm_intstack_top(void);
#endif

#if CONFIG_ARCH_INTERRUPTSTACK > 7
void weak_function arm_initialize_stack(void);
#endif

/* Exception handling logic unique to the Cortex-M family */

#if defined(CONFIG_ARCH_ARMV6M) || defined(CONFIG_ARCH_ARMV7M) || \
Expand Down
19 changes: 0 additions & 19 deletions arch/arm/src/cxd56xx/chip.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,5 @@

#ifdef __ASSEMBLY__

/****************************************************************************
* Name: setintstack
*
* Description:
* Set the current stack pointer to the "top" the correct interrupt stack
* for the current CPU.
*
****************************************************************************/

#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7
.macro setintstack, tmp1, tmp2
ldr \tmp1, =CXD56_ADSP_PID
ldr \tmp1, [\tmp1, 0]
sub \tmp1, 2 /* tmp1 = getreg32(CXD56_ADSP_PID) - 2 */
ldr \tmp2, =g_cpu_intstack_top
ldr sp, [\tmp2, \tmp1, lsl #2] /* sp = g_cpu_intstack_top[tmp1] */
.endm
#endif /* CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 7 */

#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_CXD56XX_CHIP_H */
Loading