[PATCH] arm: Fix stack alignment during interrupt handling

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Jan 13 12:34:45 UTC 2022


On a public interface, the stack pointer must be aligned on an 8-byte
boundary.  However, it may temporarily be only aligned on a 4-byte
boundary.  The interrupt handling code must ensure that the stack
pointer is properly aligned before it calls a function.  See also:

https://developer.arm.com/documentation/den0013/d/Interrupt-Handling/External-interrupt-requests/Nested-interrupt-handling

Close #4579.
---
 cpukit/score/cpu/arm/arm_exc_interrupt.S | 34 ++++++++++++------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/cpukit/score/cpu/arm/arm_exc_interrupt.S b/cpukit/score/cpu/arm/arm_exc_interrupt.S
index ddcaf945b5..43568747b1 100644
--- a/cpukit/score/cpu/arm/arm_exc_interrupt.S
+++ b/cpukit/score/cpu/arm/arm_exc_interrupt.S
@@ -7,7 +7,7 @@
  */
 
 /*
- * Copyright (c) 2009, 2016 embedded brains GmbH.  All rights reserved.
+ * Copyright (c) 2009, 2022 embedded brains GmbH.  All rights reserved.
  *
  *  embedded brains GmbH
  *  Dornierstr. 4
@@ -68,9 +68,8 @@ _ARMV4_Exception_interrupt:
 	/*
 	 * Save context.  We save the link register separately because it has
 	 * to be restored in SVC mode.  The other registers can be restored in
-	 * INT mode.  Ensure that stack remains 8 byte aligned.  Use register
-	 * necessary for the stack alignment for the stack pointer of the
-	 * interrupted context.
+	 * INT mode.  Provide a non-volatile scratch register which is used
+	 * accross function calls.
 	 */
 	stmdb	sp!, CONTEXT_LIST
 	stmdb	sp!, {NON_VOLATILE_SCRATCH, lr}
@@ -102,9 +101,6 @@ _ARMV4_Exception_interrupt:
 	cmp	r2, #0
 	moveq	sp, r1
 
-	/* Switch to Thumb-2 instructions if necessary */
-	SWITCH_FROM_ARM_TO_THUMB_2	r1
-
 	/* Increment interrupt nest and thread dispatch disable level */
 	ldr	r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
 	add	r2, #1
@@ -139,9 +135,6 @@ _ARMV4_Exception_interrupt:
 	/* Restore stack pointer */
 	mov	sp, NON_VOLATILE_SCRATCH
 
-	/* Save CPSR in non-volatile register */
-	mrs	NON_VOLATILE_SCRATCH, CPSR
-
 	/* Decrement levels and determine thread dispatch state */
 	eor	r1, r0
 	sub	r0, #1
@@ -160,9 +153,11 @@ _ARMV4_Exception_interrupt:
 	cmp	r1, #0
 	bne	.Lthread_dispatch_done
 
-	/* Thread dispatch */
+	/* Save CPSR in non-volatile register */
 	mrs	NON_VOLATILE_SCRATCH, CPSR
 
+	/* Thread dispatch */
+
 .Ldo_thread_dispatch:
 
 	/* Set ISR dispatch disable and thread dispatch disable level to one */
@@ -170,19 +165,27 @@ _ARMV4_Exception_interrupt:
 	str	r0, [SELF_CPU_CONTROL, #PER_CPU_ISR_DISPATCH_DISABLE]
 	str	r0, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
 
-	/* Call _Thread_Do_dispatch(), this function will enable interrupts */
+	/*
+	 * Call _Thread_Do_dispatch(), this function will enable interrupts.
+	 * Make sure that the stack pointer is aligned on an 8-byte boundary.
+	 */
 	mov	r0, SELF_CPU_CONTROL
 	mov	r1, NON_VOLATILE_SCRATCH
 	mov	r2, #0x80
 	bic	r1, r2
+	and	SELF_CPU_CONTROL, sp, #0x4
+	sub	sp, sp, SELF_CPU_CONTROL
 	BLX_TO_THUMB_1	_Thread_Do_dispatch
 
 	/* Disable interrupts */
 	msr	CPSR, NON_VOLATILE_SCRATCH
 
-#ifdef RTEMS_SMP
+	/*
+	 * Restore stack pointer and reinitialize SELF_CPU_CONTROL.  In SMP
+	 * configurations, we may run on a different processor.
+	 */
+	add	sp, sp, SELF_CPU_CONTROL
 	GET_SELF_CPU_CONTROL	SELF_CPU_CONTROL
-#endif
 
 	/* Check if we have to do the thread dispatch again */
 	ldrb	r0, [SELF_CPU_CONTROL, #PER_CPU_DISPATCH_NEEDED]
@@ -195,9 +198,6 @@ _ARMV4_Exception_interrupt:
 
 .Lthread_dispatch_done:
 
-	/* Switch to ARM instructions if necessary */
-	SWITCH_FROM_THUMB_2_TO_ARM
-
 #ifdef ARM_MULTILIB_VFP
 	/* Restore VFP context */
 	ldmia	sp!, {r0, r1}
-- 
2.31.1



More information about the devel mailing list