[PATCH v2 3/4] arm: Fix stack alignment during interrupt handling

Sebastian Huber sebastian.huber at embedded-brains.de
Fri Jan 14 13:17:35 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 | 39 +++++++++++++++---------
 1 file changed, 25 insertions(+), 14 deletions(-)

diff --git a/cpukit/score/cpu/arm/arm_exc_interrupt.S b/cpukit/score/cpu/arm/arm_exc_interrupt.S
index 77e57ff5e7..a239d3a7cd 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
@@ -34,6 +34,9 @@
 
 #ifdef ARM_MULTILIB_ARCH_V4
 
+#define STACK_POINTER_ADJUST r7
+#define NON_VOLATILE_SCRATCH r9
+
 #define EXCHANGE_LR r4
 #define EXCHANGE_SPSR r5
 #define EXCHANGE_CPSR r6
@@ -42,9 +45,7 @@
 #define EXCHANGE_LIST {EXCHANGE_LR, EXCHANGE_SPSR, EXCHANGE_CPSR, EXCHANGE_INT_SP}
 #define EXCHANGE_SIZE 16
 
-#define NON_VOLATILE_SCRATCH r9
-
-#define CONTEXT_LIST {r0, r1, r2, r3, EXCHANGE_LR, EXCHANGE_SPSR, r7, r12}
+#define CONTEXT_LIST {r0, r1, r2, r3, EXCHANGE_LR, EXCHANGE_SPSR, NON_VOLATILE_SCRATCH, r12}
 #define CONTEXT_SIZE 32
 
 .arm
@@ -67,12 +68,20 @@ _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 may be used
+	 * accross function calls.
 	 */
 	push	CONTEXT_LIST
-	push	{NON_VOLATILE_SCRATCH, lr}
+	push	{STACK_POINTER_ADJUST, lr}
+
+	/*
+	 * 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.  Make sure the stack pointer is aligned on an
+	 * 8-byte boundary.
+	 */
+	and	STACK_POINTER_ADJUST, sp, #0x4
+	sub	sp, sp, STACK_POINTER_ADJUST
 
 	/* Get per-CPU control of current processor */
 	GET_SELF_CPU_CONTROL	r0
@@ -138,9 +147,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, r1, r12
 	sub	r12, r12, #1
@@ -159,9 +165,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 */
@@ -203,8 +211,11 @@ _ARMV4_Exception_interrupt:
 	vmsr	FPSCR, r2
 #endif /* ARM_MULTILIB_VFP */
 
-	/* Restore NON_VOLATILE_SCRATCH register and link register */
-	pop	{NON_VOLATILE_SCRATCH, lr}
+	/* Undo stack pointer adjustment */
+	add	sp, sp, STACK_POINTER_ADJUST
+
+	/* Restore STACK_POINTER_ADJUST register and link register */
+	pop	{STACK_POINTER_ADJUST, lr}
 
 	/*
 	 * XXX: Remember and restore stack pointer.  The data on the stack is
-- 
2.31.1



More information about the devel mailing list