diff options
author | Nicolas Pitre <nico@cam.org> | 2006-01-14 11:18:08 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-01-14 11:18:08 -0500 |
commit | 2dede2d8e925f4c2cb4e136b14df127685e15dd3 (patch) | |
tree | 271b3fb300c5ac143556295d10c6736430ebed85 | |
parent | da2b1cd61903c8e9796e76be2d606584f26a78e5 (diff) |
[ARM] 3102/1: ARM EABI: stack pointer must be 64-bit aligned after a CPU exception
Patch from Nicolas Pitre
The ARM EABI says that the stack pointer has to be 64-bit aligned for
reasons already mentioned in patch #3101 when calling C functions.
We therefore must verify and adjust sp accordingly when taking an
exception from kernel mode since sp might not necessarily be 64-bit
aligned if the exception occurs in the middle of a kernel function.
If the exception occurs while in user mode then no sp fixup is needed as
long as sizeof(struct pt_regs) as well as any additional syscall data
stack space remain multiples of 8.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 17 | ||||
-rw-r--r-- | arch/arm/kernel/entry-header.S | 1 | ||||
-rw-r--r-- | include/asm-arm/ptrace.h | 8 |
3 files changed, 23 insertions, 3 deletions
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index fb8e7f4c4b37..874e6bb79405 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -105,14 +105,24 @@ common_invalid: | |||
105 | /* | 105 | /* |
106 | * SVC mode handlers | 106 | * SVC mode handlers |
107 | */ | 107 | */ |
108 | |||
109 | #if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) | ||
110 | #define SPFIX(code...) code | ||
111 | #else | ||
112 | #define SPFIX(code...) | ||
113 | #endif | ||
114 | |||
108 | .macro svc_entry | 115 | .macro svc_entry |
109 | sub sp, sp, #S_FRAME_SIZE | 116 | sub sp, sp, #S_FRAME_SIZE |
117 | SPFIX( tst sp, #4 ) | ||
118 | SPFIX( bicne sp, sp, #4 ) | ||
110 | stmib sp, {r1 - r12} | 119 | stmib sp, {r1 - r12} |
111 | 120 | ||
112 | ldmia r0, {r1 - r3} | 121 | ldmia r0, {r1 - r3} |
113 | add r5, sp, #S_SP @ here for interlock avoidance | 122 | add r5, sp, #S_SP @ here for interlock avoidance |
114 | mov r4, #-1 @ "" "" "" "" | 123 | mov r4, #-1 @ "" "" "" "" |
115 | add r0, sp, #S_FRAME_SIZE @ "" "" "" "" | 124 | add r0, sp, #S_FRAME_SIZE @ "" "" "" "" |
125 | SPFIX( addne r0, r0, #4 ) | ||
116 | str r1, [sp] @ save the "real" r0 copied | 126 | str r1, [sp] @ save the "real" r0 copied |
117 | @ from the exception stack | 127 | @ from the exception stack |
118 | 128 | ||
@@ -303,7 +313,14 @@ __pabt_svc: | |||
303 | 313 | ||
304 | /* | 314 | /* |
305 | * User mode handlers | 315 | * User mode handlers |
316 | * | ||
317 | * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE | ||
306 | */ | 318 | */ |
319 | |||
320 | #if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7) | ||
321 | #error "sizeof(struct pt_regs) must be a multiple of 8" | ||
322 | #endif | ||
323 | |||
307 | .macro usr_entry | 324 | .macro usr_entry |
308 | sub sp, sp, #S_FRAME_SIZE | 325 | sub sp, sp, #S_FRAME_SIZE |
309 | stmib sp, {r1 - r12} | 326 | stmib sp, {r1 - r12} |
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 648cfff93138..55c99cdab7d6 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S | |||
@@ -19,6 +19,7 @@ | |||
19 | @ | 19 | @ |
20 | @ Most of the stack format comes from struct pt_regs, but with | 20 | @ Most of the stack format comes from struct pt_regs, but with |
21 | @ the addition of 8 bytes for storing syscall args 5 and 6. | 21 | @ the addition of 8 bytes for storing syscall args 5 and 6. |
22 | @ This _must_ remain a multiple of 8 for EABI. | ||
22 | @ | 23 | @ |
23 | #define S_OFF 8 | 24 | #define S_OFF 8 |
24 | 25 | ||
diff --git a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h index 4377e22b7e1a..f40948d54448 100644 --- a/include/asm-arm/ptrace.h +++ b/include/asm-arm/ptrace.h | |||
@@ -60,9 +60,11 @@ | |||
60 | 60 | ||
61 | #ifndef __ASSEMBLY__ | 61 | #ifndef __ASSEMBLY__ |
62 | 62 | ||
63 | /* this struct defines the way the registers are stored on the | 63 | /* |
64 | stack during a system call. */ | 64 | * This struct defines the way the registers are stored on the |
65 | 65 | * stack during a system call. Note that sizeof(struct pt_regs) | |
66 | * has to be a multiple of 8. | ||
67 | */ | ||
66 | struct pt_regs { | 68 | struct pt_regs { |
67 | long uregs[18]; | 69 | long uregs[18]; |
68 | }; | 70 | }; |