Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /* |
3 | * linux/arch/sh/kernel/signal.c | |
4 | * | |
5 | * Copyright (C) 1991, 1992 Linus Torvalds | |
6 | * | |
7 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson | |
8 | * | |
9 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima | |
10 | * | |
11 | */ | |
1da177e4 | 12 | #include <linux/sched.h> |
68db0cf1 | 13 | #include <linux/sched/task_stack.h> |
1da177e4 LT |
14 | #include <linux/mm.h> |
15 | #include <linux/smp.h> | |
1da177e4 LT |
16 | #include <linux/kernel.h> |
17 | #include <linux/signal.h> | |
18 | #include <linux/errno.h> | |
19 | #include <linux/wait.h> | |
20 | #include <linux/ptrace.h> | |
21 | #include <linux/unistd.h> | |
22 | #include <linux/stddef.h> | |
23 | #include <linux/tty.h> | |
19f9a34f | 24 | #include <linux/elf.h> |
1da177e4 LT |
25 | #include <linux/personality.h> |
26 | #include <linux/binfmts.h> | |
b66d51cb | 27 | #include <linux/io.h> |
ab99c733 | 28 | #include <linux/tracehook.h> |
1da177e4 | 29 | #include <asm/ucontext.h> |
7c0f6ba6 | 30 | #include <linux/uaccess.h> |
1da177e4 LT |
31 | #include <asm/pgtable.h> |
32 | #include <asm/cacheflush.h> | |
fa43972f | 33 | #include <asm/syscalls.h> |
9bbafce2 | 34 | #include <asm/fpu.h> |
1da177e4 | 35 | |
3bc24a1a PM |
36 | struct fdpic_func_descriptor { |
37 | unsigned long text; | |
38 | unsigned long GOT; | |
39 | }; | |
40 | ||
2fc742f8 CS |
41 | /* |
42 | * The following define adds a 64 byte gap between the signal | |
43 | * stack frame and previous contents of the stack. This allows | |
44 | * frame unwinding in a function epilogue but only if a frame | |
45 | * pointer is used in the function. This is necessary because | |
46 | * current gcc compilers (<4.3) do not generate unwind info on | |
47 | * SH for function epilogues. | |
48 | */ | |
49 | #define UNWINDGUARD 64 | |
50 | ||
1da177e4 LT |
51 | /* |
52 | * Do a signal return; undo the signal stack. | |
53 | */ | |
54 | ||
55 | #define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ | |
11cbb70e | 56 | #if defined(CONFIG_CPU_SH2) |
9d4436a6 YS |
57 | #define TRAP_NOARG 0xc320 /* Syscall w/no args (NR in R3) */ |
58 | #else | |
59 | #define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) */ | |
60 | #endif | |
1da177e4 LT |
61 | #define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ |
62 | ||
63 | struct sigframe | |
64 | { | |
65 | struct sigcontext sc; | |
66 | unsigned long extramask[_NSIG_WORDS-1]; | |
67 | u16 retcode[8]; | |
68 | }; | |
69 | ||
70 | struct rt_sigframe | |
71 | { | |
72 | struct siginfo info; | |
73 | struct ucontext uc; | |
74 | u16 retcode[8]; | |
75 | }; | |
76 | ||
77 | #ifdef CONFIG_SH_FPU | |
78 | static inline int restore_sigcontext_fpu(struct sigcontext __user *sc) | |
79 | { | |
80 | struct task_struct *tsk = current; | |
81 | ||
eaa47704 | 82 | if (!(boot_cpu_data.flags & CPU_HAS_FPU)) |
1da177e4 LT |
83 | return 0; |
84 | ||
85 | set_used_math(); | |
0ea820cf | 86 | return __copy_from_user(&tsk->thread.xstate->hardfpu, &sc->sc_fpregs[0], |
1da177e4 LT |
87 | sizeof(long)*(16*2+2)); |
88 | } | |
89 | ||
90 | static inline int save_sigcontext_fpu(struct sigcontext __user *sc, | |
91 | struct pt_regs *regs) | |
92 | { | |
93 | struct task_struct *tsk = current; | |
94 | ||
eaa47704 | 95 | if (!(boot_cpu_data.flags & CPU_HAS_FPU)) |
1da177e4 LT |
96 | return 0; |
97 | ||
a46808e1 AV |
98 | if (!used_math()) |
99 | return __put_user(0, &sc->sc_ownedfp); | |
1da177e4 | 100 | |
a46808e1 AV |
101 | if (__put_user(1, &sc->sc_ownedfp)) |
102 | return -EFAULT; | |
1da177e4 LT |
103 | |
104 | /* This will cause a "finit" to be triggered by the next | |
105 | attempted FPU operation by the 'current' process. | |
106 | */ | |
107 | clear_used_math(); | |
108 | ||
109 | unlazy_fpu(tsk, regs); | |
0ea820cf | 110 | return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.xstate->hardfpu, |
1da177e4 LT |
111 | sizeof(long)*(16*2+2)); |
112 | } | |
113 | #endif /* CONFIG_SH_FPU */ | |
114 | ||
115 | static int | |
116 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p) | |
117 | { | |
118 | unsigned int err = 0; | |
119 | ||
120 | #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) | |
121 | COPY(regs[1]); | |
122 | COPY(regs[2]); COPY(regs[3]); | |
123 | COPY(regs[4]); COPY(regs[5]); | |
124 | COPY(regs[6]); COPY(regs[7]); | |
125 | COPY(regs[8]); COPY(regs[9]); | |
126 | COPY(regs[10]); COPY(regs[11]); | |
127 | COPY(regs[12]); COPY(regs[13]); | |
128 | COPY(regs[14]); COPY(regs[15]); | |
129 | COPY(gbr); COPY(mach); | |
130 | COPY(macl); COPY(pr); | |
131 | COPY(sr); COPY(pc); | |
132 | #undef COPY | |
133 | ||
134 | #ifdef CONFIG_SH_FPU | |
eaa47704 | 135 | if (boot_cpu_data.flags & CPU_HAS_FPU) { |
1da177e4 LT |
136 | int owned_fp; |
137 | struct task_struct *tsk = current; | |
138 | ||
139 | regs->sr |= SR_FD; /* Release FPU */ | |
140 | clear_fpu(tsk, regs); | |
141 | clear_used_math(); | |
a46808e1 | 142 | err |= __get_user (owned_fp, &sc->sc_ownedfp); |
1da177e4 LT |
143 | if (owned_fp) |
144 | err |= restore_sigcontext_fpu(sc); | |
145 | } | |
146 | #endif | |
147 | ||
148 | regs->tra = -1; /* disable syscall checks */ | |
149 | err |= __get_user(*r0_p, &sc->sc_regs[0]); | |
150 | return err; | |
151 | } | |
152 | ||
abafe5d9 | 153 | asmlinkage int sys_sigreturn(void) |
1da177e4 | 154 | { |
abafe5d9 | 155 | struct pt_regs *regs = current_pt_regs(); |
f0bc814c | 156 | struct sigframe __user *frame = (struct sigframe __user *)regs->regs[15]; |
1da177e4 LT |
157 | sigset_t set; |
158 | int r0; | |
159 | ||
1bec157a | 160 | /* Always make any pending restarted system calls return -EINTR */ |
f56141e3 | 161 | current->restart_block.fn = do_no_restart_syscall; |
1bec157a | 162 | |
1da177e4 LT |
163 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
164 | goto badframe; | |
165 | ||
166 | if (__get_user(set.sig[0], &frame->sc.oldmask) | |
167 | || (_NSIG_WORDS > 1 | |
168 | && __copy_from_user(&set.sig[1], &frame->extramask, | |
169 | sizeof(frame->extramask)))) | |
170 | goto badframe; | |
171 | ||
5e047fa1 | 172 | set_current_blocked(&set); |
1da177e4 | 173 | |
f0bc814c | 174 | if (restore_sigcontext(regs, &frame->sc, &r0)) |
1da177e4 LT |
175 | goto badframe; |
176 | return r0; | |
177 | ||
178 | badframe: | |
179 | force_sig(SIGSEGV, current); | |
180 | return 0; | |
181 | } | |
182 | ||
abafe5d9 | 183 | asmlinkage int sys_rt_sigreturn(void) |
1da177e4 | 184 | { |
abafe5d9 | 185 | struct pt_regs *regs = current_pt_regs(); |
f0bc814c | 186 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15]; |
1da177e4 | 187 | sigset_t set; |
1da177e4 LT |
188 | int r0; |
189 | ||
1bec157a | 190 | /* Always make any pending restarted system calls return -EINTR */ |
f56141e3 | 191 | current->restart_block.fn = do_no_restart_syscall; |
1bec157a | 192 | |
1da177e4 LT |
193 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
194 | goto badframe; | |
195 | ||
196 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | |
197 | goto badframe; | |
198 | ||
5e047fa1 | 199 | set_current_blocked(&set); |
1da177e4 | 200 | |
f0bc814c | 201 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) |
1da177e4 LT |
202 | goto badframe; |
203 | ||
7a879a94 | 204 | if (restore_altstack(&frame->uc.uc_stack)) |
1da177e4 | 205 | goto badframe; |
1da177e4 LT |
206 | |
207 | return r0; | |
208 | ||
209 | badframe: | |
210 | force_sig(SIGSEGV, current); | |
211 | return 0; | |
3aeb884b | 212 | } |
1da177e4 LT |
213 | |
214 | /* | |
215 | * Set up a signal frame. | |
216 | */ | |
217 | ||
218 | static int | |
219 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |
220 | unsigned long mask) | |
221 | { | |
222 | int err = 0; | |
223 | ||
224 | #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) | |
225 | COPY(regs[0]); COPY(regs[1]); | |
226 | COPY(regs[2]); COPY(regs[3]); | |
227 | COPY(regs[4]); COPY(regs[5]); | |
228 | COPY(regs[6]); COPY(regs[7]); | |
229 | COPY(regs[8]); COPY(regs[9]); | |
230 | COPY(regs[10]); COPY(regs[11]); | |
231 | COPY(regs[12]); COPY(regs[13]); | |
232 | COPY(regs[14]); COPY(regs[15]); | |
233 | COPY(gbr); COPY(mach); | |
234 | COPY(macl); COPY(pr); | |
235 | COPY(sr); COPY(pc); | |
236 | #undef COPY | |
237 | ||
238 | #ifdef CONFIG_SH_FPU | |
239 | err |= save_sigcontext_fpu(sc, regs); | |
240 | #endif | |
241 | ||
242 | /* non-iBCS2 extensions.. */ | |
243 | err |= __put_user(mask, &sc->oldmask); | |
244 | ||
245 | return err; | |
246 | } | |
247 | ||
248 | /* | |
249 | * Determine which stack to use.. | |
250 | */ | |
251 | static inline void __user * | |
252 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | |
253 | { | |
254 | if (ka->sa.sa_flags & SA_ONSTACK) { | |
255 | if (sas_ss_flags(sp) == 0) | |
256 | sp = current->sas_ss_sp + current->sas_ss_size; | |
257 | } | |
258 | ||
2fc742f8 | 259 | return (void __user *)((sp - (frame_size+UNWINDGUARD)) & -8ul); |
1da177e4 LT |
260 | } |
261 | ||
19f9a34f PM |
262 | /* These symbols are defined with the addresses in the vsyscall page. |
263 | See vsyscall-trapa.S. */ | |
94455711 MF |
264 | extern void __kernel_sigreturn(void); |
265 | extern void __kernel_rt_sigreturn(void); | |
19f9a34f | 266 | |
b46e8487 RW |
267 | static int setup_frame(struct ksignal *ksig, sigset_t *set, |
268 | struct pt_regs *regs) | |
1da177e4 LT |
269 | { |
270 | struct sigframe __user *frame; | |
b46e8487 | 271 | int err = 0, sig = ksig->sig; |
1da177e4 | 272 | |
b46e8487 | 273 | frame = get_sigframe(&ksig->ka, regs->regs[15], sizeof(*frame)); |
1da177e4 LT |
274 | |
275 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | |
b46e8487 | 276 | return -EFAULT; |
1da177e4 | 277 | |
1da177e4 LT |
278 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); |
279 | ||
9f23e7e9 | 280 | if (_NSIG_WORDS > 1) |
1da177e4 LT |
281 | err |= __copy_to_user(frame->extramask, &set->sig[1], |
282 | sizeof(frame->extramask)); | |
1da177e4 LT |
283 | |
284 | /* Set up to return from userspace. If provided, use a stub | |
285 | already in userspace. */ | |
b46e8487 RW |
286 | if (ksig->ka.sa.sa_flags & SA_RESTORER) { |
287 | regs->pr = (unsigned long) ksig->ka.sa.sa_restorer; | |
19f9a34f PM |
288 | #ifdef CONFIG_VSYSCALL |
289 | } else if (likely(current->mm->context.vdso)) { | |
290 | regs->pr = VDSO_SYM(&__kernel_sigreturn); | |
291 | #endif | |
1da177e4 LT |
292 | } else { |
293 | /* Generate return code (system call to sigreturn) */ | |
294 | err |= __put_user(MOVW(7), &frame->retcode[0]); | |
9d4436a6 | 295 | err |= __put_user(TRAP_NOARG, &frame->retcode[1]); |
1da177e4 LT |
296 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); |
297 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); | |
298 | err |= __put_user(OR_R0_R0, &frame->retcode[4]); | |
299 | err |= __put_user(OR_R0_R0, &frame->retcode[5]); | |
300 | err |= __put_user(OR_R0_R0, &frame->retcode[6]); | |
301 | err |= __put_user((__NR_sigreturn), &frame->retcode[7]); | |
302 | regs->pr = (unsigned long) frame->retcode; | |
f2fb4e4f | 303 | flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode)); |
1da177e4 LT |
304 | } |
305 | ||
306 | if (err) | |
b46e8487 | 307 | return -EFAULT; |
1da177e4 LT |
308 | |
309 | /* Set up registers for signal handler */ | |
310 | regs->regs[15] = (unsigned long) frame; | |
daea906d | 311 | regs->regs[4] = sig; /* Arg for signal handler */ |
1da177e4 LT |
312 | regs->regs[5] = 0; |
313 | regs->regs[6] = (unsigned long) &frame->sc; | |
3bc24a1a PM |
314 | |
315 | if (current->personality & FDPIC_FUNCPTRS) { | |
316 | struct fdpic_func_descriptor __user *funcptr = | |
b46e8487 | 317 | (struct fdpic_func_descriptor __user *)ksig->ka.sa.sa_handler; |
3bc24a1a | 318 | |
a46808e1 AV |
319 | err |= __get_user(regs->pc, &funcptr->text); |
320 | err |= __get_user(regs->regs[12], &funcptr->GOT); | |
3bc24a1a | 321 | } else |
b46e8487 | 322 | regs->pc = (unsigned long)ksig->ka.sa.sa_handler; |
1da177e4 | 323 | |
a46808e1 | 324 | if (err) |
b46e8487 | 325 | return -EFAULT; |
a46808e1 | 326 | |
9f23e7e9 | 327 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
19c5870c | 328 | current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); |
1da177e4 | 329 | |
9f23e7e9 | 330 | return 0; |
1da177e4 LT |
331 | } |
332 | ||
b46e8487 RW |
333 | static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, |
334 | struct pt_regs *regs) | |
1da177e4 LT |
335 | { |
336 | struct rt_sigframe __user *frame; | |
b46e8487 | 337 | int err = 0, sig = ksig->sig; |
1da177e4 | 338 | |
b46e8487 | 339 | frame = get_sigframe(&ksig->ka, regs->regs[15], sizeof(*frame)); |
1da177e4 LT |
340 | |
341 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | |
b46e8487 | 342 | return -EFAULT; |
1da177e4 | 343 | |
b46e8487 | 344 | err |= copy_siginfo_to_user(&frame->info, &ksig->info); |
1da177e4 LT |
345 | |
346 | /* Create the ucontext. */ | |
347 | err |= __put_user(0, &frame->uc.uc_flags); | |
fa43972f | 348 | err |= __put_user(NULL, &frame->uc.uc_link); |
7a879a94 | 349 | err |= __save_altstack(&frame->uc.uc_stack, regs->regs[15]); |
1da177e4 LT |
350 | err |= setup_sigcontext(&frame->uc.uc_mcontext, |
351 | regs, set->sig[0]); | |
352 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | |
353 | ||
354 | /* Set up to return from userspace. If provided, use a stub | |
355 | already in userspace. */ | |
b46e8487 RW |
356 | if (ksig->ka.sa.sa_flags & SA_RESTORER) { |
357 | regs->pr = (unsigned long) ksig->ka.sa.sa_restorer; | |
19f9a34f PM |
358 | #ifdef CONFIG_VSYSCALL |
359 | } else if (likely(current->mm->context.vdso)) { | |
360 | regs->pr = VDSO_SYM(&__kernel_rt_sigreturn); | |
361 | #endif | |
1da177e4 LT |
362 | } else { |
363 | /* Generate return code (system call to rt_sigreturn) */ | |
364 | err |= __put_user(MOVW(7), &frame->retcode[0]); | |
9d4436a6 | 365 | err |= __put_user(TRAP_NOARG, &frame->retcode[1]); |
1da177e4 LT |
366 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); |
367 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); | |
368 | err |= __put_user(OR_R0_R0, &frame->retcode[4]); | |
369 | err |= __put_user(OR_R0_R0, &frame->retcode[5]); | |
370 | err |= __put_user(OR_R0_R0, &frame->retcode[6]); | |
371 | err |= __put_user((__NR_rt_sigreturn), &frame->retcode[7]); | |
372 | regs->pr = (unsigned long) frame->retcode; | |
4d2947f7 | 373 | flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode)); |
1da177e4 LT |
374 | } |
375 | ||
376 | if (err) | |
b46e8487 | 377 | return -EFAULT; |
1da177e4 LT |
378 | |
379 | /* Set up registers for signal handler */ | |
380 | regs->regs[15] = (unsigned long) frame; | |
daea906d | 381 | regs->regs[4] = sig; /* Arg for signal handler */ |
1da177e4 LT |
382 | regs->regs[5] = (unsigned long) &frame->info; |
383 | regs->regs[6] = (unsigned long) &frame->uc; | |
3bc24a1a PM |
384 | |
385 | if (current->personality & FDPIC_FUNCPTRS) { | |
386 | struct fdpic_func_descriptor __user *funcptr = | |
b46e8487 | 387 | (struct fdpic_func_descriptor __user *)ksig->ka.sa.sa_handler; |
3bc24a1a | 388 | |
a46808e1 AV |
389 | err |= __get_user(regs->pc, &funcptr->text); |
390 | err |= __get_user(regs->regs[12], &funcptr->GOT); | |
3bc24a1a | 391 | } else |
b46e8487 | 392 | regs->pc = (unsigned long)ksig->ka.sa.sa_handler; |
1da177e4 | 393 | |
a46808e1 | 394 | if (err) |
b46e8487 | 395 | return -EFAULT; |
a46808e1 | 396 | |
9f23e7e9 | 397 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
19c5870c | 398 | current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); |
1da177e4 | 399 | |
9f23e7e9 | 400 | return 0; |
1da177e4 LT |
401 | } |
402 | ||
f8b890ab PM |
403 | static inline void |
404 | handle_syscall_restart(unsigned long save_r0, struct pt_regs *regs, | |
405 | struct sigaction *sa) | |
406 | { | |
407 | /* If we're not from a syscall, bail out */ | |
408 | if (regs->tra < 0) | |
409 | return; | |
410 | ||
411 | /* check for system call restart.. */ | |
412 | switch (regs->regs[0]) { | |
413 | case -ERESTART_RESTARTBLOCK: | |
414 | case -ERESTARTNOHAND: | |
415 | no_system_call_restart: | |
416 | regs->regs[0] = -EINTR; | |
f8b890ab PM |
417 | break; |
418 | ||
419 | case -ERESTARTSYS: | |
420 | if (!(sa->sa_flags & SA_RESTART)) | |
421 | goto no_system_call_restart; | |
422 | /* fallthrough */ | |
423 | case -ERESTARTNOINTR: | |
424 | regs->regs[0] = save_r0; | |
9d56dd3b | 425 | regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); |
f8b890ab PM |
426 | break; |
427 | } | |
428 | } | |
429 | ||
1da177e4 LT |
430 | /* |
431 | * OK, we're invoking a handler | |
432 | */ | |
a610d6e6 | 433 | static void |
b46e8487 | 434 | handle_signal(struct ksignal *ksig, struct pt_regs *regs, unsigned int save_r0) |
1da177e4 | 435 | { |
b7f9a11a | 436 | sigset_t *oldset = sigmask_to_save(); |
9f23e7e9 PM |
437 | int ret; |
438 | ||
1da177e4 | 439 | /* Set up the stack frame */ |
b46e8487 RW |
440 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) |
441 | ret = setup_rt_frame(ksig, oldset, regs); | |
1da177e4 | 442 | else |
b46e8487 | 443 | ret = setup_frame(ksig, oldset, regs); |
1da177e4 | 444 | |
b46e8487 | 445 | signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP)); |
1da177e4 LT |
446 | } |
447 | ||
448 | /* | |
449 | * Note that 'init' is a special process: it doesn't get signals it doesn't | |
450 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | |
451 | * mistake. | |
452 | * | |
453 | * Note that we go through the signals twice: once to check the signals that | |
454 | * the kernel can handle, and then we build all the user-level signal handling | |
455 | * stack-frames in one go after that. | |
456 | */ | |
9f23e7e9 | 457 | static void do_signal(struct pt_regs *regs, unsigned int save_r0) |
1da177e4 | 458 | { |
b46e8487 | 459 | struct ksignal ksig; |
1da177e4 LT |
460 | |
461 | /* | |
462 | * We want the common case to go fast, which | |
463 | * is why we may in certain cases get here from | |
464 | * kernel mode. Just return without doing anything | |
465 | * if so. | |
466 | */ | |
467 | if (!user_mode(regs)) | |
9f23e7e9 | 468 | return; |
1da177e4 | 469 | |
b46e8487 RW |
470 | if (get_signal(&ksig)) { |
471 | handle_syscall_restart(save_r0, regs, &ksig.ka.sa); | |
f8b890ab | 472 | |
1da177e4 | 473 | /* Whee! Actually deliver the signal. */ |
b46e8487 | 474 | handle_signal(&ksig, regs, save_r0); |
c8bfa1fd | 475 | return; |
1da177e4 LT |
476 | } |
477 | ||
1da177e4 LT |
478 | /* Did we come from a system call? */ |
479 | if (regs->tra >= 0) { | |
480 | /* Restart the system call - no handlers present */ | |
481 | if (regs->regs[0] == -ERESTARTNOHAND || | |
482 | regs->regs[0] == -ERESTARTSYS || | |
0b892935 | 483 | regs->regs[0] == -ERESTARTNOINTR) { |
c8bfa1fd | 484 | regs->regs[0] = save_r0; |
9d56dd3b | 485 | regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); |
0b892935 | 486 | } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) { |
9d56dd3b | 487 | regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); |
0b892935 | 488 | regs->regs[3] = __NR_restart_syscall; |
1da177e4 LT |
489 | } |
490 | } | |
9f23e7e9 | 491 | |
56bfc42f PM |
492 | /* |
493 | * If there's no signal to deliver, we just put the saved sigmask | |
494 | * back. | |
495 | */ | |
51a7b448 | 496 | restore_saved_sigmask(); |
9f23e7e9 PM |
497 | } |
498 | ||
499 | asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, | |
ab99c733 | 500 | unsigned long thread_info_flags) |
9f23e7e9 PM |
501 | { |
502 | /* deal with pending signal delivery */ | |
ab99c733 | 503 | if (thread_info_flags & _TIF_SIGPENDING) |
9f23e7e9 | 504 | do_signal(regs, save_r0); |
ab99c733 PM |
505 | |
506 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | |
507 | clear_thread_flag(TIF_NOTIFY_RESUME); | |
508 | tracehook_notify_resume(regs); | |
509 | } | |
1da177e4 | 510 | } |