mirror of
https://github.com/apache/nuttx.git
synced 2026-05-23 23:28:29 +08:00
arch/arm: Remove the code copy register from xcpt to stack
since xcpt always point to the stack after the below change:
commit 7b9978883c
Author: chao.an <anchao@xiaomi.com>
Date: Tue Mar 1 01:06:24 2022 +0800
arch/arm: optimize context switch speed
The current context save implementation saves registers of each task
to xcp context, which is unnecessary because most of the arm registers are
already saved in the task stack, this commit replace the xcp context with
stack context to improve context switching performance and reduce the tcb
space occupation of tcb instance.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
committed by
Masayuki Ishikawa
parent
9288ed85e7
commit
9ae0dcd4a2
@@ -167,10 +167,7 @@ exception_common:
|
||||
*/
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
||||
setintstack r7, r6 /* SP = IRQ stack top */
|
||||
push {r1} /* Save the MSP on the interrupt stack */
|
||||
bl arm_doirq /* R0=IRQ, R1=register save area on stack */
|
||||
pop {r1} /* Recover R1=main stack pointer */
|
||||
setintstack r7, r6 /* SP = IRQ stack top */
|
||||
#else
|
||||
/* If the interrupt stack is disabled, reserve xcpcontext to ensure
|
||||
* that signal processing can have a separate xcpcontext to handle
|
||||
@@ -183,64 +180,30 @@ exception_common:
|
||||
* also the sp should be restore after arm_doirq()
|
||||
*/
|
||||
|
||||
sub r1, r1, #XCPTCONTEXT_SIZE /* Reserve signal context */
|
||||
|
||||
msr msp, r1 /* We are using the main stack pointer */
|
||||
|
||||
add r1, r1, #XCPTCONTEXT_SIZE /* Restore signal context */
|
||||
mov r2, r1 /* Reserve signal context */
|
||||
sub r2, r2, #XCPTCONTEXT_SIZE
|
||||
msr msp, r2 /* We are using the main stack pointer */
|
||||
#endif
|
||||
|
||||
bl arm_doirq /* R0=IRQ, R1=register save area on stack */
|
||||
|
||||
mrs r1, msp /* Recover R1=main stack pointer */
|
||||
#endif
|
||||
|
||||
/* On return from arm_doirq, R0 will hold a pointer to register context
|
||||
* array to use for the interrupt return. If that return value is the same
|
||||
* as current stack pointer, then things are relatively easy.
|
||||
*/
|
||||
|
||||
cmp r0, r1 /* Context switch? */
|
||||
beq 3f /* Branch if no context switch */
|
||||
|
||||
/* We are returning with a pending context switch. This case is different
|
||||
* because in this case, the register save structure does not lie on the
|
||||
* stack but, rather within a TCB structure. We'll have to copy some
|
||||
* values to the stack.
|
||||
*/
|
||||
|
||||
/* Copy the hardware-saved context to the new stack */
|
||||
|
||||
mov r2, #SW_XCPT_SIZE /* R2=Size of software-saved portion of the context array */
|
||||
add r1, r0, r2 /* R1=Address of HW save area in reg array */
|
||||
ldr r2, [r0, #(4*REG_SP)] /* R2=Value of SP before the interrupt */
|
||||
sub r2, #HW_XCPT_SIZE /* R2=Address of HW save area on the return stack */
|
||||
ldmia r1!, {r4-r7} /* Fetch four registers from the HW save area */
|
||||
stmia r2!, {r4-r7} /* Copy four registers to the return stack */
|
||||
ldmia r1!, {r4-r7} /* Fetch four registers from the HW save area */
|
||||
stmia r2!, {r4-r7} /* Copy four registers to the return stack */
|
||||
|
||||
/* Restore the register contents */
|
||||
|
||||
mov r1, r0
|
||||
|
||||
3:
|
||||
/* We are returning with no context switch. We simply need to "unwind"
|
||||
* the same stack frame that we created at entry.
|
||||
* array to use for the interrupt return.
|
||||
*/
|
||||
|
||||
/* Recover R8-R11 and EXEC_RETURN (5 registers) */
|
||||
|
||||
mov r2, #(4*REG_R8) /* R2=Offset to R8 storage */
|
||||
add r0, r1, r2 /* R0=Address of R8 storage */
|
||||
add r1, r0, r2 /* R1=Address of R8 storage */
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
ldmia r0!, {r2-r6} /* Recover R8-R11 and R14 (5 registers)*/
|
||||
ldmia r1!, {r2-r6} /* Recover R8-R11 and R14 (5 registers)*/
|
||||
mov r8, r2 /* Move to position in high registers */
|
||||
mov r9, r3
|
||||
mov r10, r4
|
||||
mov r11, r5
|
||||
mov r14, r6 /* EXEC_RETURN */
|
||||
#else
|
||||
ldmia r0!, {r2-r5} /* Recover R8-R11 and R14 (5 registers)*/
|
||||
ldmia r1!, {r2-r5} /* Recover R8-R11 (4 registers)*/
|
||||
mov r8, r2 /* Move to position in high registers */
|
||||
mov r9, r3
|
||||
mov r10, r4
|
||||
@@ -251,7 +214,7 @@ exception_common:
|
||||
* the stack pointer as it was on entry to the exception handler.
|
||||
*/
|
||||
|
||||
ldmia r1!, {r2-r7} /* Recover R4-R7 + 2 temp values */
|
||||
ldmia r0!, {r2-r7} /* Recover R4-R7 + 2 temp values */
|
||||
mov r1, #HW_XCPT_SIZE /* R1=Size of hardware-saved portion of the context array */
|
||||
sub r1, r2, r1 /* R1=Value of MSP/PSP on exception entry */
|
||||
|
||||
@@ -262,14 +225,14 @@ exception_common:
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
mov r0, r14 /* Copy high register to low register */
|
||||
lsl r0, #(31 - EXC_RETURN_PROCESS_BITNO) /* Move to bit 31 */
|
||||
bmi 5f /* Test bit 31 */
|
||||
bmi 3f /* Test bit 31 */
|
||||
msr msp, r1 /* R1=The main stack pointer */
|
||||
b 6f
|
||||
b 4f
|
||||
|
||||
5:
|
||||
3:
|
||||
msr psp, r1 /* R1=The process stack pointer */
|
||||
|
||||
6:
|
||||
4:
|
||||
#else
|
||||
msr msp, r1 /* R1=The main stack pointer */
|
||||
ldr r0, =EXC_RETURN_PRIVTHR /* R0=EXC_RETURN to privileged mode */
|
||||
|
||||
@@ -188,10 +188,6 @@ exception_common:
|
||||
|
||||
mov r1, sp
|
||||
|
||||
/* Also save the top of the stack in a preserved register */
|
||||
|
||||
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
|
||||
@@ -199,9 +195,12 @@ exception_common:
|
||||
*/
|
||||
|
||||
setintstack r2, r3 /* SP = IRQ stack top */
|
||||
|
||||
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
|
||||
#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 the interrupt stack is disabled, reserve xcpcontext to ensure
|
||||
* that signal processing can have a separate xcpcontext to handle
|
||||
* signal context (reference: arm_schedulesigaction.c):
|
||||
@@ -213,77 +212,22 @@ exception_common:
|
||||
* also the sp should be restore after arm_doirq()
|
||||
*/
|
||||
|
||||
sub r4, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */
|
||||
|
||||
/* 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).
|
||||
*/
|
||||
|
||||
bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */
|
||||
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 */
|
||||
#endif
|
||||
|
||||
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
|
||||
|
||||
/* If the interrupt stack is disabled, restore the signal context */
|
||||
|
||||
add r4, r4, #XCPTCONTEXT_SIZE /* Restore signal context */
|
||||
#endif
|
||||
|
||||
mov r1, r4 /* Recover R1=main stack pointer */
|
||||
|
||||
/* On return from arm_doirq, R0 will hold a pointer to register context
|
||||
* array to use for the interrupt return. If that return value is the same
|
||||
* as current stack pointer, then things are relatively easy.
|
||||
* array to use for the interrupt return.
|
||||
*/
|
||||
|
||||
cmp r0, r1 /* Context switch? */
|
||||
beq 2f /* Branch if no context switch */
|
||||
|
||||
/* We are returning with a pending context switch. This case is different
|
||||
* because in this case, the register save structure does not lie on the
|
||||
* stack but, rather within a TCB structure. We'll have to copy some
|
||||
* values to the stack.
|
||||
*/
|
||||
|
||||
/* Copy the hardware-saved context to the stack, and restore the software
|
||||
* saved context directly.
|
||||
*
|
||||
* XXX In the normal case, it appears that this entire operation is unnecessary;
|
||||
* context switch time would be improved if we could work out when the stack
|
||||
* is dirty and avoid the work...
|
||||
*/
|
||||
|
||||
add r1, r0, #SW_XCPT_SIZE /* R1=Address of HW save area in reg array */
|
||||
ldmia r1!, {r4-r11} /* Fetch eight registers in HW save area */
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
vldmia r1!, {s0-s15} /* Fetch sixteen FP registers in HW save area */
|
||||
ldmia r1, {r2-r3} /* Fetch FPSCR and Reserved in HW save area */
|
||||
#endif
|
||||
ldr r1, [r0, #(4*REG_SP)] /* R1=Value of SP before interrupt */
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
stmdb r1!, {r2-r3} /* Store FPSCR and Reserved on the return stack */
|
||||
vstmdb r1!, {s0-s15} /* Store sixteen FP registers on the return stack */
|
||||
#endif
|
||||
stmdb r1!, {r4-r11} /* Store eight registers on the return stack */
|
||||
ldmia r0!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
vldmia r0, {s16-s31} /* Recover S16-S31 */
|
||||
vldmia r0!, {s16-s31} /* Recover S16-S31 */
|
||||
#endif
|
||||
|
||||
b 3f /* Re-join common logic */
|
||||
|
||||
2:
|
||||
/* We are returning with no context switch. We simply need to "unwind"
|
||||
* the same stack frame that we created at entry.
|
||||
*/
|
||||
|
||||
ldmia r1!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
vldmia r1!, {s16-s31} /* Recover S16-S31 */
|
||||
#endif
|
||||
|
||||
3:
|
||||
/* The EXC_RETURN value tells us whether we are returning on the MSP or PSP
|
||||
*/
|
||||
|
||||
@@ -295,21 +239,21 @@ exception_common:
|
||||
|
||||
mrs r2, control /* R2=Contents of the control register */
|
||||
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */
|
||||
beq 4f /* Branch if privileged */
|
||||
beq 2f /* Branch if privileged */
|
||||
|
||||
orr r2, r2, #1 /* Unprivileged mode */
|
||||
msr psp, r1 /* R1=The process stack pointer */
|
||||
b 5f
|
||||
4:
|
||||
msr psp, r0 /* R0=The process stack pointer */
|
||||
b 3f
|
||||
2:
|
||||
bic r2, r2, #1 /* Privileged mode */
|
||||
msr msp, r1 /* R1=The main stack pointer */
|
||||
5:
|
||||
msr msp, r0 /* R0=The main stack pointer */
|
||||
3:
|
||||
msr control, r2 /* Save the updated control register */
|
||||
#else
|
||||
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */
|
||||
ite eq /* Next two instructions conditional */
|
||||
msreq msp, r1 /* R1=The main stack pointer */
|
||||
msrne psp, r1 /* R1=The process stack pointer */
|
||||
msreq msp, r0 /* R0=The main stack pointer */
|
||||
msrne psp, r0 /* R0=The process stack pointer */
|
||||
#endif
|
||||
|
||||
/* Restore the interrupt state */
|
||||
|
||||
@@ -193,9 +193,12 @@ exception_common:
|
||||
*/
|
||||
|
||||
setintstack r2, r3 /* SP = IRQ stack top */
|
||||
|
||||
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
|
||||
#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 the interrupt stack is disabled, reserve xcpcontext to ensure
|
||||
* that signal processing can have a separate xcpcontext to handle
|
||||
* signal context (reference: arm_schedulesigaction.c):
|
||||
@@ -207,31 +210,19 @@ exception_common:
|
||||
* also the sp should be restore after arm_doirq()
|
||||
*/
|
||||
|
||||
sub r4, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */
|
||||
|
||||
/* 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).
|
||||
*/
|
||||
|
||||
bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */
|
||||
sub r2, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */
|
||||
bic r2, r2, #7 /* Get the stack pointer with 8-byte alignment */
|
||||
mov sp, r2 /* Instantiate the aligned stack */
|
||||
|
||||
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
|
||||
|
||||
/* If the interrupt stack is disabled, restore the signal context */
|
||||
|
||||
add r4, r4, #XCPTCONTEXT_SIZE /* Restore signal context */
|
||||
#endif
|
||||
|
||||
mov r1, r4 /* Recover R1=main stack pointer */
|
||||
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
|
||||
|
||||
/* On return from arm_doirq, R0 will hold a pointer to register context
|
||||
* array to use for the interrupt return. If that return value is the same
|
||||
* as current stack pointer, then things are relatively easy.
|
||||
*/
|
||||
|
||||
cmp r0, r1 /* Context switch? */
|
||||
cmp r0, r4 /* Context switch? */
|
||||
beq 2f /* Branch if no context switch */
|
||||
|
||||
/* We are returning with a pending context switch.
|
||||
@@ -253,56 +244,30 @@ exception_common:
|
||||
bl arm_restorefpu /* Restore the FPU registers */
|
||||
#endif
|
||||
|
||||
/* We are returning with a pending context switch. This case is different
|
||||
* because in this case, the register save structure does not lie in the
|
||||
* stack but, rather, within a TCB structure. We'll have to copy some
|
||||
* values to the stack.
|
||||
*/
|
||||
|
||||
add r1, r0, #SW_XCPT_SIZE /* R1=Address of HW save area in reg array */
|
||||
ldmia r1, {r4-r11} /* Fetch eight registers in HW save area */
|
||||
ldr r1, [r0, #(4*REG_SP)] /* R1=Value of SP before interrupt */
|
||||
stmdb r1!, {r4-r11} /* Store eight registers in HW save area */
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
ldmia r0, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
|
||||
#else
|
||||
ldmia r0, {r2-r11} /* Recover R4-R11 + 2 temp values */
|
||||
#endif
|
||||
b 3f /* Re-join common logic */
|
||||
|
||||
/* We are returning with no context switch. We simply need to "unwind"
|
||||
* the same stack frame that we created
|
||||
*
|
||||
* Here:
|
||||
* r1 = Address of the return stack (same as r0)
|
||||
*/
|
||||
|
||||
2:
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
ldmia r1!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
|
||||
ldmia r0!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
|
||||
#else
|
||||
ldmia r1!, {r2-r11} /* Recover R4-R11 + 2 temp values */
|
||||
ldmia r0!, {r2-r11} /* Recover R4-R11 + 2 temp values */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
/* Skip over the block of memory reserved for floating pointer register
|
||||
* save. Then R1 is the address of the HW save area
|
||||
* save. Then R0 is the address of the HW save area
|
||||
*/
|
||||
|
||||
add r1, #(4*SW_FPU_REGS)
|
||||
add r0, #(4*SW_FPU_REGS)
|
||||
#endif
|
||||
|
||||
/* Set up to return from the exception
|
||||
*
|
||||
* Here:
|
||||
* r1 = Address on the target thread's stack position at the start of
|
||||
* r0 = Address on the target thread's stack position at the start of
|
||||
* the registers saved by hardware
|
||||
* r3 = primask or basepri
|
||||
* r4-r11 = restored register values
|
||||
*/
|
||||
|
||||
3:
|
||||
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
/* The EXC_RETURN value will be 0xfffffff9 (privileged thread) or 0xfffffff1
|
||||
* (handler mode) if the stack is on the MSP. It can only be on the PSP if
|
||||
@@ -311,18 +276,18 @@ exception_common:
|
||||
|
||||
mrs r2, control /* R2=Contents of the control register */
|
||||
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */
|
||||
beq 4f /* Branch if privileged */
|
||||
beq 3f /* Branch if privileged */
|
||||
|
||||
orr r2, r2, #1 /* Unprivileged mode */
|
||||
msr psp, r1 /* R1=The process stack pointer */
|
||||
b 5f
|
||||
4:
|
||||
msr psp, r0 /* R0=The process stack pointer */
|
||||
b 4f
|
||||
3:
|
||||
bic r2, r2, #1 /* Privileged mode */
|
||||
msr msp, r1 /* R1=The main stack pointer */
|
||||
5:
|
||||
msr msp, r0 /* R0=The main stack pointer */
|
||||
4:
|
||||
msr control, r2 /* Save the updated control register */
|
||||
#else
|
||||
msr msp, r1 /* Recover the return MSP value */
|
||||
msr msp, r0 /* Recover the return MSP value */
|
||||
|
||||
/* Preload r14 with the special return value first (so that the return
|
||||
* actually occurs with interrupts still disabled).
|
||||
|
||||
@@ -204,10 +204,6 @@ exception_common:
|
||||
|
||||
mov r1, sp
|
||||
|
||||
/* Also save the top of the stack in a preserved register */
|
||||
|
||||
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
|
||||
@@ -215,9 +211,12 @@ exception_common:
|
||||
*/
|
||||
|
||||
setintstack r2, r3 /* SP = IRQ stack top */
|
||||
|
||||
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
|
||||
#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 the interrupt stack is disabled, reserve xcpcontext to ensure
|
||||
* that signal processing can have a separate xcpcontext to handle
|
||||
* signal context (reference: arm_schedulesigaction.c):
|
||||
@@ -229,85 +228,26 @@ exception_common:
|
||||
* also the sp should be restore after arm_doirq()
|
||||
*/
|
||||
|
||||
sub r4, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */
|
||||
|
||||
/* 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).
|
||||
*/
|
||||
|
||||
bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */
|
||||
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 */
|
||||
#endif
|
||||
|
||||
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
|
||||
|
||||
/* If the interrupt stack is disabled, restore the signal context */
|
||||
|
||||
add r4, r4, #XCPTCONTEXT_SIZE /* Restore signal context */
|
||||
#endif
|
||||
|
||||
mov r1, r4 /* Recover R1=main stack pointer */
|
||||
|
||||
/* On return from arm_doirq, R0 will hold a pointer to register context
|
||||
* array to use for the interrupt return. If that return value is the same
|
||||
* as current stack pointer, then things are relatively easy.
|
||||
* array to use for the interrupt return.
|
||||
*/
|
||||
|
||||
cmp r0, r1 /* Context switch? */
|
||||
beq 2f /* Branch if no context switch */
|
||||
|
||||
/* We are returning with a pending context switch. This case is different
|
||||
* because in this case, the register save structure does not lie on the
|
||||
* stack but, rather within a TCB structure. We'll have to copy some
|
||||
* values to the stack.
|
||||
*/
|
||||
|
||||
/* Copy the hardware-saved context to the stack, and restore the software
|
||||
* saved context directly.
|
||||
*
|
||||
* XXX In the normal case, it appears that this entire operation is unnecessary;
|
||||
* context switch time would be improved if we could work out when the stack
|
||||
* is dirty and avoid the work...
|
||||
*/
|
||||
|
||||
add r1, r0, #SW_XCPT_SIZE /* R1=Address of HW save area in reg array */
|
||||
ldmia r1!, {r4-r11} /* Fetch eight registers in HW save area */
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
vldmia r1!, {s0-s15} /* Fetch sixteen FP registers in HW save area */
|
||||
ldmia r1, {r2-r3} /* Fetch FPSCR and Reserved in HW save area */
|
||||
#endif
|
||||
ldr r1, [r0, #(4*REG_SP)] /* R1=Value of SP before interrupt */
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
stmdb r1!, {r2-r3} /* Store FPSCR and Reserved on the return stack */
|
||||
vstmdb r1!, {s0-s15} /* Store sixteen FP registers on the return stack */
|
||||
#endif
|
||||
stmdb r1!, {r4-r11} /* Store eight registers on the return stack */
|
||||
ldmia r0!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
vldmia r0!, {s16-s31} /* Recover S16-S31 */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
ldmia r0, {r0} /* Get psplim/msplim */
|
||||
ldmia r0!, {r1} /* Get psplim/msplim */
|
||||
#endif
|
||||
|
||||
b 3f /* Re-join common logic */
|
||||
|
||||
2:
|
||||
/* We are returning with no context switch. We simply need to "unwind"
|
||||
* the same stack frame that we created at entry.
|
||||
*/
|
||||
|
||||
ldmia r1!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
vldmia r1!, {s16-s31} /* Recover S16-S31 */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
ldmia r1!, {r0} /* Get psplim/msplim */
|
||||
#endif
|
||||
|
||||
3:
|
||||
/* The EXC_RETURN value tells us whether we are returning on the MSP or PSP
|
||||
*/
|
||||
|
||||
@@ -319,33 +259,33 @@ exception_common:
|
||||
|
||||
mrs r2, control /* R2=Contents of the control register */
|
||||
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */
|
||||
beq 4f /* Branch if privileged */
|
||||
beq 2f /* Branch if privileged */
|
||||
|
||||
orr r2, r2, #1 /* Unprivileged mode */
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
msr psplim, r0
|
||||
msr psplim, r1
|
||||
#endif
|
||||
msr psp, r1 /* R1=The process stack pointer */
|
||||
b 5f
|
||||
4:
|
||||
msr psp, r0 /* R0=The process stack pointer */
|
||||
b 3f
|
||||
2:
|
||||
bic r2, r2, #1 /* Privileged mode */
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
msr msplim, r0
|
||||
msr msplim, r1
|
||||
#endif
|
||||
msr msp, r1 /* R1=The main stack pointer */
|
||||
5:
|
||||
msr msp, r0 /* R0=The main stack pointer */
|
||||
3:
|
||||
msr control, r2 /* Save the updated control register */
|
||||
#else
|
||||
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
itete eq
|
||||
msreq msplim, r0
|
||||
msrne psplim, r0
|
||||
msreq msplim, r1
|
||||
msrne psplim, r1
|
||||
#else
|
||||
ite eq /* Next two instructions conditional */
|
||||
#endif
|
||||
msreq msp, r1 /* R1=The main stack pointer */
|
||||
msrne psp, r1 /* R1=The process stack pointer */
|
||||
msreq msp, r0 /* R0=The main stack pointer */
|
||||
msrne psp, r0 /* R0=The process stack pointer */
|
||||
#endif
|
||||
|
||||
/* Restore the interrupt state */
|
||||
|
||||
@@ -210,9 +210,12 @@ exception_common:
|
||||
*/
|
||||
|
||||
setintstack r2, r3 /* SP = IRQ stack top */
|
||||
|
||||
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
|
||||
#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 the interrupt stack is disabled, reserve xcpcontext to ensure
|
||||
* that signal processing can have a separate xcpcontext to handle
|
||||
* signal context (reference: arm_schedulesigaction.c):
|
||||
@@ -224,31 +227,18 @@ exception_common:
|
||||
* also the sp should be restore after arm_doirq()
|
||||
*/
|
||||
|
||||
sub r4, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */
|
||||
|
||||
/* 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).
|
||||
*/
|
||||
|
||||
bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */
|
||||
sub r2, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */
|
||||
bic r2, r2, #7 /* Get the stack pointer with 8-byte alignment */
|
||||
mov sp, r2 /* Instantiate the aligned stack */
|
||||
#endif
|
||||
|
||||
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
|
||||
|
||||
/* If the interrupt stack is disabled, restore the signal context */
|
||||
|
||||
add r4, r4, #XCPTCONTEXT_SIZE /* Restore signal context */
|
||||
#endif
|
||||
|
||||
mov r1, r4 /* Recover R1=main stack pointer */
|
||||
|
||||
/* On return from arm_doirq, R0 will hold a pointer to register context
|
||||
* array to use for the interrupt return. If that return value is the same
|
||||
* as current stack pointer, then things are relatively easy.
|
||||
* array to use for the interrupt return.
|
||||
*/
|
||||
|
||||
cmp r0, r1 /* Context switch? */
|
||||
cmp r0, r4 /* Context switch? */
|
||||
beq 2f /* Branch if no context switch */
|
||||
|
||||
/* We are returning with a pending context switch.
|
||||
@@ -270,63 +260,34 @@ exception_common:
|
||||
bl arm_restorefpu /* Restore the FPU registers */
|
||||
#endif
|
||||
|
||||
/* We are returning with a pending context switch. This case is different
|
||||
* because in this case, the register save structure does not lie in the
|
||||
* stack but, rather, within a TCB structure. We'll have to copy some
|
||||
* values to the stack.
|
||||
*/
|
||||
|
||||
add r1, r0, #SW_XCPT_SIZE /* R1=Address of HW save area in reg array */
|
||||
ldmia r1, {r4-r11} /* Fetch eight registers in HW save area */
|
||||
ldr r1, [r0, #(4*REG_SP)] /* R1=Value of SP before interrupt */
|
||||
stmdb r1!, {r4-r11} /* Store eight registers in HW save area */
|
||||
2:
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
ldmia r0!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
|
||||
#else
|
||||
ldmia r0!, {r2-r11} /* Recover R4-R11 + 2 temp values */
|
||||
#endif
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
ldmia r0, {r0} /* Get psplim/msplim*/
|
||||
#endif
|
||||
b 3f /* Re-join common logic */
|
||||
|
||||
/* We are returning with no context switch. We simply need to "unwind"
|
||||
* the same stack frame that we created
|
||||
*
|
||||
* Here:
|
||||
* r1 = Address of the return stack (same as r0)
|
||||
*/
|
||||
|
||||
2:
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
ldmia r1!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */
|
||||
#else
|
||||
ldmia r1!, {r2-r11} /* Recover R4-R11 + 2 temp values */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_FPU
|
||||
/* Skip over the block of memory reserved for floating pointer register
|
||||
* save. Then R1 is the address of the HW save area
|
||||
*/
|
||||
|
||||
add r1, #(4*SW_FPU_REGS)
|
||||
add r0, #(4*SW_FPU_REGS)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
ldmia r1!, {r0} /* Get psplim/msplim */
|
||||
ldmia r0!, {r1} /* Get psplim/msplim */
|
||||
#endif
|
||||
|
||||
/* Set up to return from the exception
|
||||
*
|
||||
* Here:
|
||||
* r1 = Address on the target thread's stack position at the start of
|
||||
* r0 = Address on the target thread's stack position at the start of
|
||||
* the registers saved by hardware
|
||||
* r3 = primask or basepri
|
||||
* r4-r11 = restored register values
|
||||
*/
|
||||
|
||||
3:
|
||||
|
||||
#ifdef CONFIG_BUILD_PROTECTED
|
||||
/* The EXC_RETURN value will be 0xfffffff9 (privileged thread) or 0xfffffff1
|
||||
* (handler mode) if the stack is on the MSP. It can only be on the PSP if
|
||||
@@ -335,27 +296,27 @@ exception_common:
|
||||
|
||||
mrs r2, control /* R2=Contents of the control register */
|
||||
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */
|
||||
beq 4f /* Branch if privileged */
|
||||
beq 3f /* Branch if privileged */
|
||||
|
||||
orr r2, r2, #1 /* Unprivileged mode */
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
msr psplim, r0
|
||||
msr psplim, r1
|
||||
#endif
|
||||
msr psp, r1 /* R1=The process stack pointer */
|
||||
b 5f
|
||||
4:
|
||||
msr psp, r0 /* R1=The process stack pointer */
|
||||
b 4f
|
||||
3:
|
||||
bic r2, r2, #1 /* Privileged mode */
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
msr msplim, r0
|
||||
msr msplim, r1
|
||||
#endif
|
||||
msr msp, r1 /* R1=The main stack pointer */
|
||||
5:
|
||||
msr msp, r0 /* R1=The main stack pointer */
|
||||
4:
|
||||
msr control, r2 /* Save the updated control register */
|
||||
#else
|
||||
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
|
||||
msr msplim, r0
|
||||
msr msplim, r1
|
||||
#endif
|
||||
msr msp, r1 /* Recover the return MSP value */
|
||||
msr msp, r0 /* Recover the return MSP value */
|
||||
|
||||
/* Preload r14 with the special return value first (so that the return
|
||||
* actually occurs with interrupts still disabled).
|
||||
|
||||
Reference in New Issue
Block a user