diff options
-rw-r--r-- | arch/sh/include/asm/syscall_64.h | 76 | ||||
-rw-r--r-- | arch/sh/kernel/signal_32.c | 1 | ||||
-rw-r--r-- | arch/sh/kernel/signal_64.c | 63 |
3 files changed, 108 insertions, 32 deletions
diff --git a/arch/sh/include/asm/syscall_64.h b/arch/sh/include/asm/syscall_64.h index bcaaa8ca4d70..e95f3ae30aff 100644 --- a/arch/sh/include/asm/syscall_64.h +++ b/arch/sh/include/asm/syscall_64.h | |||
@@ -1,6 +1,80 @@ | |||
1 | #ifndef __ASM_SH_SYSCALL_64_H | 1 | #ifndef __ASM_SH_SYSCALL_64_H |
2 | #define __ASM_SH_SYSCALL_64_H | 2 | #define __ASM_SH_SYSCALL_64_H |
3 | 3 | ||
4 | #include <asm-generic/syscall.h> | 4 | #include <linux/kernel.h> |
5 | #include <linux/sched.h> | ||
6 | #include <asm/ptrace.h> | ||
7 | |||
8 | /* The system call number is given by the user in R9 */ | ||
9 | static inline long syscall_get_nr(struct task_struct *task, | ||
10 | struct pt_regs *regs) | ||
11 | { | ||
12 | return (regs->syscall_nr >= 0) ? regs->regs[9] : -1L; | ||
13 | } | ||
14 | |||
15 | static inline void syscall_rollback(struct task_struct *task, | ||
16 | struct pt_regs *regs) | ||
17 | { | ||
18 | /* | ||
19 | * XXX: This needs some thought. On SH we don't | ||
20 | * save away the original R9 value anywhere. | ||
21 | */ | ||
22 | } | ||
23 | |||
24 | static inline bool syscall_has_error(struct pt_regs *regs) | ||
25 | { | ||
26 | return (regs->sr & 0x1) ? true : false; | ||
27 | } | ||
28 | static inline void syscall_set_error(struct pt_regs *regs) | ||
29 | { | ||
30 | regs->sr |= 0x1; | ||
31 | } | ||
32 | static inline void syscall_clear_error(struct pt_regs *regs) | ||
33 | { | ||
34 | regs->sr &= ~0x1; | ||
35 | } | ||
36 | |||
37 | static inline long syscall_get_error(struct task_struct *task, | ||
38 | struct pt_regs *regs) | ||
39 | { | ||
40 | return syscall_has_error(regs) ? regs->regs[9] : 0; | ||
41 | } | ||
42 | |||
43 | static inline long syscall_get_return_value(struct task_struct *task, | ||
44 | struct pt_regs *regs) | ||
45 | { | ||
46 | return regs->regs[9]; | ||
47 | } | ||
48 | |||
49 | static inline void syscall_set_return_value(struct task_struct *task, | ||
50 | struct pt_regs *regs, | ||
51 | int error, long val) | ||
52 | { | ||
53 | if (error) { | ||
54 | syscall_set_error(regs); | ||
55 | regs->regs[9] = -error; | ||
56 | } else { | ||
57 | syscall_clear_error(regs); | ||
58 | regs->regs[9] = val; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | static inline void syscall_get_arguments(struct task_struct *task, | ||
63 | struct pt_regs *regs, | ||
64 | unsigned int i, unsigned int n, | ||
65 | unsigned long *args) | ||
66 | { | ||
67 | BUG_ON(i + n > 6); | ||
68 | memcpy(args, ®s->reg[2 + i], n * sizeof(args[0])); | ||
69 | } | ||
70 | |||
71 | static inline void syscall_set_arguments(struct task_struct *task, | ||
72 | struct pt_regs *regs, | ||
73 | unsigned int i, unsigned int n, | ||
74 | const unsigned long *args) | ||
75 | { | ||
76 | BUG_ON(i + n > 6); | ||
77 | memcpy(®s->reg[2 + i], args, n * sizeof(args[0])); | ||
78 | } | ||
5 | 79 | ||
6 | #endif /* __ASM_SH_SYSCALL_64_H */ | 80 | #endif /* __ASM_SH_SYSCALL_64_H */ |
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 69d09c0b3498..77c21bde376a 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
@@ -533,7 +533,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
533 | { | 533 | { |
534 | int ret; | 534 | int ret; |
535 | 535 | ||
536 | |||
537 | /* Set up the stack frame */ | 536 | /* Set up the stack frame */ |
538 | if (ka->sa.sa_flags & SA_SIGINFO) | 537 | if (ka->sa.sa_flags & SA_SIGINFO) |
539 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 538 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 08828ddd97ff..b22fdfaaa191 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
@@ -47,6 +47,34 @@ static int | |||
47 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 47 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
48 | sigset_t *oldset, struct pt_regs * regs); | 48 | sigset_t *oldset, struct pt_regs * regs); |
49 | 49 | ||
50 | static inline void | ||
51 | handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa) | ||
52 | { | ||
53 | /* If we're not from a syscall, bail out */ | ||
54 | if (regs->syscall_nr < 0) | ||
55 | return; | ||
56 | |||
57 | /* check for system call restart.. */ | ||
58 | switch (regs->regs[REG_RET]) { | ||
59 | case -ERESTART_RESTARTBLOCK: | ||
60 | case -ERESTARTNOHAND: | ||
61 | no_system_call_restart: | ||
62 | regs->regs[REG_RET] = -EINTR; | ||
63 | regs->sr |= 1; | ||
64 | break; | ||
65 | |||
66 | case -ERESTARTSYS: | ||
67 | if (!(sa->sa_flags & SA_RESTART)) | ||
68 | goto no_system_call_restart; | ||
69 | /* fallthrough */ | ||
70 | case -ERESTARTNOINTR: | ||
71 | /* Decode syscall # */ | ||
72 | regs->regs[REG_RET] = regs->syscall_nr; | ||
73 | regs->pc -= 4; | ||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | |||
50 | /* | 78 | /* |
51 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 79 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
52 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 80 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
@@ -81,6 +109,9 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
81 | 109 | ||
82 | signr = get_signal_to_deliver(&info, &ka, regs, 0); | 110 | signr = get_signal_to_deliver(&info, &ka, regs, 0); |
83 | if (signr > 0) { | 111 | if (signr > 0) { |
112 | if (regs->sr & 1) | ||
113 | handle_syscall_restart(regs, &ka.sa); | ||
114 | |||
84 | /* Whee! Actually deliver the signal. */ | 115 | /* Whee! Actually deliver the signal. */ |
85 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { | 116 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { |
86 | /* | 117 | /* |
@@ -128,7 +159,6 @@ no_signal: | |||
128 | /* | 159 | /* |
129 | * Atomically swap in the new signal mask, and wait for a signal. | 160 | * Atomically swap in the new signal mask, and wait for a signal. |
130 | */ | 161 | */ |
131 | |||
132 | asmlinkage int | 162 | asmlinkage int |
133 | sys_sigsuspend(old_sigset_t mask, | 163 | sys_sigsuspend(old_sigset_t mask, |
134 | unsigned long r3, unsigned long r4, unsigned long r5, | 164 | unsigned long r3, unsigned long r4, unsigned long r5, |
@@ -234,20 +264,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
234 | return do_sigaltstack(uss, uoss, REF_REG_SP); | 264 | return do_sigaltstack(uss, uoss, REF_REG_SP); |
235 | } | 265 | } |
236 | 266 | ||
237 | |||
238 | /* | 267 | /* |
239 | * Do a signal return; undo the signal stack. | 268 | * Do a signal return; undo the signal stack. |
240 | */ | 269 | */ |
241 | 270 | struct sigframe { | |
242 | struct sigframe | ||
243 | { | ||
244 | struct sigcontext sc; | 271 | struct sigcontext sc; |
245 | unsigned long extramask[_NSIG_WORDS-1]; | 272 | unsigned long extramask[_NSIG_WORDS-1]; |
246 | long long retcode[2]; | 273 | long long retcode[2]; |
247 | }; | 274 | }; |
248 | 275 | ||
249 | struct rt_sigframe | 276 | struct rt_sigframe { |
250 | { | ||
251 | struct siginfo __user *pinfo; | 277 | struct siginfo __user *pinfo; |
252 | void *puc; | 278 | void *puc; |
253 | struct siginfo info; | 279 | struct siginfo info; |
@@ -449,7 +475,6 @@ badframe: | |||
449 | /* | 475 | /* |
450 | * Set up a signal frame. | 476 | * Set up a signal frame. |
451 | */ | 477 | */ |
452 | |||
453 | static int | 478 | static int |
454 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | 479 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
455 | unsigned long mask) | 480 | unsigned long mask) |
@@ -714,34 +739,12 @@ give_sigsegv: | |||
714 | /* | 739 | /* |
715 | * OK, we're invoking a handler | 740 | * OK, we're invoking a handler |
716 | */ | 741 | */ |
717 | |||
718 | static int | 742 | static int |
719 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 743 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
720 | sigset_t *oldset, struct pt_regs * regs) | 744 | sigset_t *oldset, struct pt_regs * regs) |
721 | { | 745 | { |
722 | int ret; | 746 | int ret; |
723 | 747 | ||
724 | /* Are we from a system call? */ | ||
725 | if (regs->syscall_nr >= 0) { | ||
726 | /* If so, check system call restarting.. */ | ||
727 | switch (regs->regs[REG_RET]) { | ||
728 | case -ERESTART_RESTARTBLOCK: | ||
729 | case -ERESTARTNOHAND: | ||
730 | no_system_call_restart: | ||
731 | regs->regs[REG_RET] = -EINTR; | ||
732 | break; | ||
733 | |||
734 | case -ERESTARTSYS: | ||
735 | if (!(ka->sa.sa_flags & SA_RESTART)) | ||
736 | goto no_system_call_restart; | ||
737 | /* fallthrough */ | ||
738 | case -ERESTARTNOINTR: | ||
739 | /* Decode syscall # */ | ||
740 | regs->regs[REG_RET] = regs->syscall_nr; | ||
741 | regs->pc -= 4; | ||
742 | } | ||
743 | } | ||
744 | |||
745 | /* Set up the stack frame */ | 748 | /* Set up the stack frame */ |
746 | if (ka->sa.sa_flags & SA_SIGINFO) | 749 | if (ka->sa.sa_flags & SA_SIGINFO) |
747 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 750 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |