diff options
Diffstat (limited to 'arch/m32r/kernel/signal.c')
-rw-r--r-- | arch/m32r/kernel/signal.c | 103 |
1 files changed, 41 insertions, 62 deletions
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 144b0f124fc7..a08697f0886d 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c | |||
@@ -30,35 +30,6 @@ | |||
30 | 30 | ||
31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
32 | 32 | ||
33 | int do_signal(struct pt_regs *, sigset_t *); | ||
34 | |||
35 | asmlinkage int | ||
36 | sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, | ||
37 | unsigned long r2, unsigned long r3, unsigned long r4, | ||
38 | unsigned long r5, unsigned long r6, struct pt_regs *regs) | ||
39 | { | ||
40 | sigset_t newset; | ||
41 | |||
42 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
43 | if (sigsetsize != sizeof(sigset_t)) | ||
44 | return -EINVAL; | ||
45 | |||
46 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
47 | return -EFAULT; | ||
48 | sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
49 | |||
50 | spin_lock_irq(¤t->sighand->siglock); | ||
51 | current->saved_sigmask = current->blocked; | ||
52 | current->blocked = newset; | ||
53 | recalc_sigpending(); | ||
54 | spin_unlock_irq(¤t->sighand->siglock); | ||
55 | |||
56 | current->state = TASK_INTERRUPTIBLE; | ||
57 | schedule(); | ||
58 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
59 | return -ERESTARTNOHAND; | ||
60 | } | ||
61 | |||
62 | asmlinkage int | 33 | asmlinkage int |
63 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 34 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
64 | unsigned long r2, unsigned long r3, unsigned long r4, | 35 | unsigned long r2, unsigned long r3, unsigned long r4, |
@@ -218,7 +189,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | |||
218 | return (void __user *)((sp - frame_size) & -8ul); | 189 | return (void __user *)((sp - frame_size) & -8ul); |
219 | } | 190 | } |
220 | 191 | ||
221 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 192 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
222 | sigset_t *set, struct pt_regs *regs) | 193 | sigset_t *set, struct pt_regs *regs) |
223 | { | 194 | { |
224 | struct rt_sigframe __user *frame; | 195 | struct rt_sigframe __user *frame; |
@@ -275,22 +246,34 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
275 | current->comm, current->pid, frame, regs->pc); | 246 | current->comm, current->pid, frame, regs->pc); |
276 | #endif | 247 | #endif |
277 | 248 | ||
278 | return; | 249 | return 0; |
279 | 250 | ||
280 | give_sigsegv: | 251 | give_sigsegv: |
281 | force_sigsegv(sig, current); | 252 | force_sigsegv(sig, current); |
253 | return -EFAULT; | ||
254 | } | ||
255 | |||
256 | static int prev_insn(struct pt_regs *regs) | ||
257 | { | ||
258 | u16 inst; | ||
259 | if (get_user(inst, (u16 __user *)(regs->bpc - 2))) | ||
260 | return -EFAULT; | ||
261 | if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | ||
262 | regs->bpc -= 2; | ||
263 | else | ||
264 | regs->bpc -= 4; | ||
265 | regs->syscall_nr = -1; | ||
266 | return 0; | ||
282 | } | 267 | } |
283 | 268 | ||
284 | /* | 269 | /* |
285 | * OK, we're invoking a handler | 270 | * OK, we're invoking a handler |
286 | */ | 271 | */ |
287 | 272 | ||
288 | static void | 273 | static int |
289 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | 274 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, |
290 | sigset_t *oldset, struct pt_regs *regs) | 275 | sigset_t *oldset, struct pt_regs *regs) |
291 | { | 276 | { |
292 | unsigned short inst; | ||
293 | |||
294 | /* Are we from a system call? */ | 277 | /* Are we from a system call? */ |
295 | if (regs->syscall_nr >= 0) { | 278 | if (regs->syscall_nr >= 0) { |
296 | /* If so, check system call restarting.. */ | 279 | /* If so, check system call restarting.. */ |
@@ -308,16 +291,14 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
308 | /* fallthrough */ | 291 | /* fallthrough */ |
309 | case -ERESTARTNOINTR: | 292 | case -ERESTARTNOINTR: |
310 | regs->r0 = regs->orig_r0; | 293 | regs->r0 = regs->orig_r0; |
311 | inst = *(unsigned short *)(regs->bpc - 2); | 294 | if (prev_insn(regs) < 0) |
312 | if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | 295 | return -EFAULT; |
313 | regs->bpc -= 2; | ||
314 | else | ||
315 | regs->bpc -= 4; | ||
316 | } | 296 | } |
317 | } | 297 | } |
318 | 298 | ||
319 | /* Set up the stack frame */ | 299 | /* Set up the stack frame */ |
320 | setup_rt_frame(sig, ka, info, oldset, regs); | 300 | if (setup_rt_frame(sig, ka, info, oldset, regs)) |
301 | return -EFAULT; | ||
321 | 302 | ||
322 | spin_lock_irq(¤t->sighand->siglock); | 303 | spin_lock_irq(¤t->sighand->siglock); |
323 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 304 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
@@ -325,6 +306,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
325 | sigaddset(¤t->blocked,sig); | 306 | sigaddset(¤t->blocked,sig); |
326 | recalc_sigpending(); | 307 | recalc_sigpending(); |
327 | spin_unlock_irq(¤t->sighand->siglock); | 308 | spin_unlock_irq(¤t->sighand->siglock); |
309 | return 0; | ||
328 | } | 310 | } |
329 | 311 | ||
330 | /* | 312 | /* |
@@ -332,12 +314,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
332 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 314 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
333 | * mistake. | 315 | * mistake. |
334 | */ | 316 | */ |
335 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | 317 | static void do_signal(struct pt_regs *regs) |
336 | { | 318 | { |
337 | siginfo_t info; | 319 | siginfo_t info; |
338 | int signr; | 320 | int signr; |
339 | struct k_sigaction ka; | 321 | struct k_sigaction ka; |
340 | unsigned short inst; | 322 | sigset_t *oldset; |
341 | 323 | ||
342 | /* | 324 | /* |
343 | * We want the common case to go fast, which | 325 | * We want the common case to go fast, which |
@@ -346,12 +328,14 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
346 | * if so. | 328 | * if so. |
347 | */ | 329 | */ |
348 | if (!user_mode(regs)) | 330 | if (!user_mode(regs)) |
349 | return 1; | 331 | return; |
350 | 332 | ||
351 | if (try_to_freeze()) | 333 | if (try_to_freeze()) |
352 | goto no_signal; | 334 | goto no_signal; |
353 | 335 | ||
354 | if (!oldset) | 336 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
337 | oldset = ¤t->saved_sigmask; | ||
338 | else | ||
355 | oldset = ¤t->blocked; | 339 | oldset = ¤t->blocked; |
356 | 340 | ||
357 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 341 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
@@ -363,8 +347,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
363 | */ | 347 | */ |
364 | 348 | ||
365 | /* Whee! Actually deliver the signal. */ | 349 | /* Whee! Actually deliver the signal. */ |
366 | handle_signal(signr, &ka, &info, oldset, regs); | 350 | if (handle_signal(signr, &ka, &info, oldset, regs) == 0) |
367 | return 1; | 351 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
352 | |||
353 | return; | ||
368 | } | 354 | } |
369 | 355 | ||
370 | no_signal: | 356 | no_signal: |
@@ -375,31 +361,24 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
375 | regs->r0 == -ERESTARTSYS || | 361 | regs->r0 == -ERESTARTSYS || |
376 | regs->r0 == -ERESTARTNOINTR) { | 362 | regs->r0 == -ERESTARTNOINTR) { |
377 | regs->r0 = regs->orig_r0; | 363 | regs->r0 = regs->orig_r0; |
378 | inst = *(unsigned short *)(regs->bpc - 2); | 364 | prev_insn(regs); |
379 | if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | 365 | } else if (regs->r0 == -ERESTART_RESTARTBLOCK){ |
380 | regs->bpc -= 2; | ||
381 | else | ||
382 | regs->bpc -= 4; | ||
383 | } | ||
384 | if (regs->r0 == -ERESTART_RESTARTBLOCK){ | ||
385 | regs->r0 = regs->orig_r0; | 366 | regs->r0 = regs->orig_r0; |
386 | regs->r7 = __NR_restart_syscall; | 367 | regs->r7 = __NR_restart_syscall; |
387 | inst = *(unsigned short *)(regs->bpc - 2); | 368 | prev_insn(regs); |
388 | if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | ||
389 | regs->bpc -= 2; | ||
390 | else | ||
391 | regs->bpc -= 4; | ||
392 | } | 369 | } |
393 | } | 370 | } |
394 | return 0; | 371 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { |
372 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
373 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
374 | } | ||
395 | } | 375 | } |
396 | 376 | ||
397 | /* | 377 | /* |
398 | * notification of userspace execution resumption | 378 | * notification of userspace execution resumption |
399 | * - triggered by current->work.notify_resume | 379 | * - triggered by current->work.notify_resume |
400 | */ | 380 | */ |
401 | void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, | 381 | void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags) |
402 | __u32 thread_info_flags) | ||
403 | { | 382 | { |
404 | /* Pending single-step? */ | 383 | /* Pending single-step? */ |
405 | if (thread_info_flags & _TIF_SINGLESTEP) | 384 | if (thread_info_flags & _TIF_SINGLESTEP) |
@@ -407,7 +386,7 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, | |||
407 | 386 | ||
408 | /* deal with pending signal delivery */ | 387 | /* deal with pending signal delivery */ |
409 | if (thread_info_flags & _TIF_SIGPENDING) | 388 | if (thread_info_flags & _TIF_SIGPENDING) |
410 | do_signal(regs,oldset); | 389 | do_signal(regs); |
411 | 390 | ||
412 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 391 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
413 | clear_thread_flag(TIF_NOTIFY_RESUME); | 392 | clear_thread_flag(TIF_NOTIFY_RESUME); |