aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2006-01-18 17:38:47 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-01-18 17:38:47 -0500
commitfcca538b83f2984095f15f0f90f6c7686e3a32d4 (patch)
treebf113e29cb4cc4b13900814a3c7ada4884c94a18 /arch/arm/kernel
parent1230b4046b9da77ccb83ef2eaffc54dc4a96093a (diff)
[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: Nicolas Pitre <nico@cam.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/signal.c29
-rw-r--r--arch/arm/kernel/signal.h2
2 files changed, 19 insertions, 12 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 765922bcf9e7..a0cd0a90a10d 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -30,15 +30,21 @@
30#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)) 30#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn))
31 31
32/* 32/*
33 * With EABI, the syscall number has to be loaded into r7.
34 */
35#define MOV_R7_NR_SIGRETURN (0xe3a07000 | (__NR_sigreturn - __NR_SYSCALL_BASE))
36#define MOV_R7_NR_RT_SIGRETURN (0xe3a07000 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
37
38/*
33 * For Thumb syscalls, we pass the syscall number via r7. We therefore 39 * For Thumb syscalls, we pass the syscall number via r7. We therefore
34 * need two 16-bit instructions. 40 * need two 16-bit instructions.
35 */ 41 */
36#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE)) 42#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
37#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) 43#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
38 44
39const unsigned long sigreturn_codes[4] = { 45const unsigned long sigreturn_codes[7] = {
40 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, 46 MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
41 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN 47 MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
42}; 48};
43 49
44static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); 50static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
@@ -189,7 +195,7 @@ struct aux_sigframe {
189struct sigframe { 195struct sigframe {
190 struct sigcontext sc; 196 struct sigcontext sc;
191 unsigned long extramask[_NSIG_WORDS-1]; 197 unsigned long extramask[_NSIG_WORDS-1];
192 unsigned long retcode; 198 unsigned long retcode[2];
193 struct aux_sigframe aux __attribute__((aligned(8))); 199 struct aux_sigframe aux __attribute__((aligned(8)));
194}; 200};
195 201
@@ -198,7 +204,7 @@ struct rt_sigframe {
198 void __user *puc; 204 void __user *puc;
199 struct siginfo info; 205 struct siginfo info;
200 struct ucontext uc; 206 struct ucontext uc;
201 unsigned long retcode; 207 unsigned long retcode[2];
202 struct aux_sigframe aux __attribute__((aligned(8))); 208 struct aux_sigframe aux __attribute__((aligned(8)));
203}; 209};
204 210
@@ -436,12 +442,13 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
436 if (ka->sa.sa_flags & SA_RESTORER) { 442 if (ka->sa.sa_flags & SA_RESTORER) {
437 retcode = (unsigned long)ka->sa.sa_restorer; 443 retcode = (unsigned long)ka->sa.sa_restorer;
438 } else { 444 } else {
439 unsigned int idx = thumb; 445 unsigned int idx = thumb << 1;
440 446
441 if (ka->sa.sa_flags & SA_SIGINFO) 447 if (ka->sa.sa_flags & SA_SIGINFO)
442 idx += 2; 448 idx += 3;
443 449
444 if (__put_user(sigreturn_codes[idx], rc)) 450 if (__put_user(sigreturn_codes[idx], rc) ||
451 __put_user(sigreturn_codes[idx+1], rc+1))
445 return 1; 452 return 1;
446 453
447 if (cpsr & MODE32_BIT) { 454 if (cpsr & MODE32_BIT) {
@@ -456,7 +463,7 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
456 * the return code written onto the stack. 463 * the return code written onto the stack.
457 */ 464 */
458 flush_icache_range((unsigned long)rc, 465 flush_icache_range((unsigned long)rc,
459 (unsigned long)(rc + 1)); 466 (unsigned long)(rc + 2));
460 467
461 retcode = ((unsigned long)rc) + thumb; 468 retcode = ((unsigned long)rc) + thumb;
462 } 469 }
@@ -488,7 +495,7 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg
488 } 495 }
489 496
490 if (err == 0) 497 if (err == 0)
491 err = setup_return(regs, ka, &frame->retcode, frame, usig); 498 err = setup_return(regs, ka, frame->retcode, frame, usig);
492 499
493 return err; 500 return err;
494} 501}
@@ -522,7 +529,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
522 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 529 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
523 530
524 if (err == 0) 531 if (err == 0)
525 err = setup_return(regs, ka, &frame->retcode, frame, usig); 532 err = setup_return(regs, ka, frame->retcode, frame, usig);
526 533
527 if (err == 0) { 534 if (err == 0) {
528 /* 535 /*
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
index 91d26faca62b..9991049c522d 100644
--- a/arch/arm/kernel/signal.h
+++ b/arch/arm/kernel/signal.h
@@ -9,4 +9,4 @@
9 */ 9 */
10#define KERN_SIGRETURN_CODE 0xffff0500 10#define KERN_SIGRETURN_CODE 0xffff0500
11 11
12extern const unsigned long sigreturn_codes[4]; 12extern const unsigned long sigreturn_codes[7];