Commit fcca538b authored by Nicolas Pitre's avatar Nicolas Pitre Committed by Russell King

[ARM] 3270/1: ARM EABI: fix sigreturn and rt_sigreturn

Patch from Nicolas Pitre

The signal return path consists of user code provided by the kernel.
Since a syscall is used, it has to be updated to work with EABI.

Noticed by Daniel Jacobowitz.
Signed-off-by: default avatarNicolas Pitre <nico@cam.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 1230b404
...@@ -29,6 +29,12 @@ ...@@ -29,6 +29,12 @@
#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)) #define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn))
#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)) #define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn))
/*
* With EABI, the syscall number has to be loaded into r7.
*/
#define MOV_R7_NR_SIGRETURN (0xe3a07000 | (__NR_sigreturn - __NR_SYSCALL_BASE))
#define MOV_R7_NR_RT_SIGRETURN (0xe3a07000 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
/* /*
* For Thumb syscalls, we pass the syscall number via r7. We therefore * For Thumb syscalls, we pass the syscall number via r7. We therefore
* need two 16-bit instructions. * need two 16-bit instructions.
...@@ -36,9 +42,9 @@ ...@@ -36,9 +42,9 @@
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE)) #define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) #define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
const unsigned long sigreturn_codes[4] = { const unsigned long sigreturn_codes[7] = {
SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
}; };
static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
...@@ -189,7 +195,7 @@ struct aux_sigframe { ...@@ -189,7 +195,7 @@ struct aux_sigframe {
struct sigframe { struct sigframe {
struct sigcontext sc; struct sigcontext sc;
unsigned long extramask[_NSIG_WORDS-1]; unsigned long extramask[_NSIG_WORDS-1];
unsigned long retcode; unsigned long retcode[2];
struct aux_sigframe aux __attribute__((aligned(8))); struct aux_sigframe aux __attribute__((aligned(8)));
}; };
...@@ -198,7 +204,7 @@ struct rt_sigframe { ...@@ -198,7 +204,7 @@ struct rt_sigframe {
void __user *puc; void __user *puc;
struct siginfo info; struct siginfo info;
struct ucontext uc; struct ucontext uc;
unsigned long retcode; unsigned long retcode[2];
struct aux_sigframe aux __attribute__((aligned(8))); struct aux_sigframe aux __attribute__((aligned(8)));
}; };
...@@ -436,12 +442,13 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, ...@@ -436,12 +442,13 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
if (ka->sa.sa_flags & SA_RESTORER) { if (ka->sa.sa_flags & SA_RESTORER) {
retcode = (unsigned long)ka->sa.sa_restorer; retcode = (unsigned long)ka->sa.sa_restorer;
} else { } else {
unsigned int idx = thumb; unsigned int idx = thumb << 1;
if (ka->sa.sa_flags & SA_SIGINFO) if (ka->sa.sa_flags & SA_SIGINFO)
idx += 2; idx += 3;
if (__put_user(sigreturn_codes[idx], rc)) if (__put_user(sigreturn_codes[idx], rc) ||
__put_user(sigreturn_codes[idx+1], rc+1))
return 1; return 1;
if (cpsr & MODE32_BIT) { if (cpsr & MODE32_BIT) {
...@@ -456,7 +463,7 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, ...@@ -456,7 +463,7 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
* the return code written onto the stack. * the return code written onto the stack.
*/ */
flush_icache_range((unsigned long)rc, flush_icache_range((unsigned long)rc,
(unsigned long)(rc + 1)); (unsigned long)(rc + 2));
retcode = ((unsigned long)rc) + thumb; retcode = ((unsigned long)rc) + thumb;
} }
...@@ -488,7 +495,7 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg ...@@ -488,7 +495,7 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg
} }
if (err == 0) if (err == 0)
err = setup_return(regs, ka, &frame->retcode, frame, usig); err = setup_return(regs, ka, frame->retcode, frame, usig);
return err; return err;
} }
...@@ -522,7 +529,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, ...@@ -522,7 +529,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err == 0) if (err == 0)
err = setup_return(regs, ka, &frame->retcode, frame, usig); err = setup_return(regs, ka, frame->retcode, frame, usig);
if (err == 0) { if (err == 0) {
/* /*
......
...@@ -9,4 +9,4 @@ ...@@ -9,4 +9,4 @@
*/ */
#define KERN_SIGRETURN_CODE 0xffff0500 #define KERN_SIGRETURN_CODE 0xffff0500
extern const unsigned long sigreturn_codes[4]; extern const unsigned long sigreturn_codes[7];
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment