| From 0a0f7362b0367634a2d5cb7c96226afc116f19c9 Mon Sep 17 00:00:00 2001 |
| From: Ivan Kokshaysky <ink@unseen.parts> |
| Date: Tue, 4 Feb 2025 23:35:23 +0100 |
| Subject: alpha: make stack 16-byte aligned (most cases) |
| |
| From: Ivan Kokshaysky <ink@unseen.parts> |
| |
| commit 0a0f7362b0367634a2d5cb7c96226afc116f19c9 upstream. |
| |
| The problem is that GCC expects 16-byte alignment of the incoming stack |
| since early 2004, as Maciej found out [1]: |
| Having actually dug speculatively I can see that the psABI was changed in |
| GCC 3.5 with commit e5e10fb4a350 ("re PR target/14539 (128-bit long double |
| improperly aligned)") back in Mar 2004, when the stack pointer alignment |
| was increased from 8 bytes to 16 bytes, and arch/alpha/kernel/entry.S has |
| various suspicious stack pointer adjustments, starting with SP_OFF which |
| is not a whole multiple of 16. |
| |
| Also, as Magnus noted, "ALPHA Calling Standard" [2] required the same: |
| D.3.1 Stack Alignment |
| This standard requires that stacks be octaword aligned at the time a |
| new procedure is invoked. |
| |
| However: |
| - the "normal" kernel stack is always misaligned by 8 bytes, thanks to |
| the odd number of 64-bit words in 'struct pt_regs', which is the very |
| first thing pushed onto the kernel thread stack; |
| - syscall, fault, interrupt etc. handlers may, or may not, receive aligned |
| stack depending on numerous factors. |
| |
| Somehow we got away with it until recently, when we ended up with |
| a stack corruption in kernel/smp.c:smp_call_function_single() due to |
| its use of 32-byte aligned local data and the compiler doing clever |
| things allocating it on the stack. |
| |
| This adds padding between the PAL-saved and kernel-saved registers |
| so that 'struct pt_regs' have an even number of 64-bit words. |
| This makes the stack properly aligned for most of the kernel |
| code, except two handlers which need special threatment. |
| |
| Note: struct pt_regs doesn't belong in uapi/asm; this should be fixed, |
| but let's put this off until later. |
| |
| Link: https://lore.kernel.org/rcu/alpine.DEB.2.21.2501130248010.18889@angie.orcam.me.uk/ [1] |
| Link: https://bitsavers.org/pdf/dec/alpha/Alpha_Calling_Standard_Rev_2.0_19900427.pdf [2] |
| |
| Cc: stable@vger.kernel.org |
| Tested-by: Maciej W. Rozycki <macro@orcam.me.uk> |
| Tested-by: Magnus Lindholm <linmag7@gmail.com> |
| Tested-by: Matt Turner <mattst88@gmail.com> |
| Reviewed-by: Maciej W. Rozycki <macro@orcam.me.uk> |
| Signed-off-by: Ivan Kokshaysky <ink@unseen.parts> |
| Signed-off-by: Matt Turner <mattst88@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/alpha/include/uapi/asm/ptrace.h | 2 ++ |
| 1 file changed, 2 insertions(+) |
| |
| --- a/arch/alpha/include/uapi/asm/ptrace.h |
| +++ b/arch/alpha/include/uapi/asm/ptrace.h |
| @@ -42,6 +42,8 @@ struct pt_regs { |
| unsigned long trap_a0; |
| unsigned long trap_a1; |
| unsigned long trap_a2; |
| +/* This makes the stack 16-byte aligned as GCC expects */ |
| + unsigned long __pad0; |
| /* These are saved by PAL-code: */ |
| unsigned long ps; |
| unsigned long pc; |