aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2006-09-27 04:27:00 -0400
committerPaul Mundt <lethal@linux-sh.org>2006-09-27 04:27:00 -0400
commit9f23e7e94f7083d9705b595cbd6b30972be6fbbb (patch)
tree5fc6e90a9e361dca2e56bb03327078a2eb88cb4c /arch/sh/kernel
parenta2d1a5fae6296c2a3ac1aaa982c95464c46c0585 (diff)
sh: pselect6 and ppoll, along with signal trampoline rework.
This implements support for ppoll() and pselect6().. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/entry.S8
-rw-r--r--arch/sh/kernel/signal.c137
-rw-r--r--arch/sh/kernel/syscalls.S31
3 files changed, 85 insertions, 91 deletions
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
index fcbf50d4ee10..fd5fe2349f20 100644
--- a/arch/sh/kernel/entry.S
+++ b/arch/sh/kernel/entry.S
@@ -371,12 +371,12 @@ work_pending:
371 ! r8: current_thread_info 371 ! r8: current_thread_info
372 ! t: result of "tst #_TIF_NEED_RESCHED, r0" 372 ! t: result of "tst #_TIF_NEED_RESCHED, r0"
373 bf/s work_resched 373 bf/s work_resched
374 tst #_TIF_SIGPENDING, r0 374 tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
375work_notifysig: 375work_notifysig:
376 bt/s restore_all 376 bt/s restore_all
377 mov r15, r4 377 mov r15, r4
378 mov #0, r5 378 mov r12, r5 ! set arg1(save_r0)
379 mov r12, r6 ! set arg2(save_r0) 379 mov r0, r6
380 mov.l 2f, r1 380 mov.l 2f, r1
381 mova restore_all, r0 381 mova restore_all, r0
382 jmp @r1 382 jmp @r1
@@ -414,7 +414,7 @@ work_resched:
414 414
415 .align 2 415 .align 2
4161: .long schedule 4161: .long schedule
4172: .long do_signal 4172: .long do_notify_resume
418 418
419 .align 2 419 .align 2
420syscall_exit_work: 420syscall_exit_work:
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index eb6a3b97e46c..2f1c9545b49f 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -29,13 +29,10 @@
29#include <asm/pgtable.h> 29#include <asm/pgtable.h>
30#include <asm/cacheflush.h> 30#include <asm/cacheflush.h>
31 31
32#define DEBUG_SIG 0 32#undef DEBUG
33 33
34#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 34#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
35 35
36asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset,
37 unsigned int save_r0);
38
39/* 36/*
40 * Atomically swap in the new signal mask, and wait for a signal. 37 * Atomically swap in the new signal mask, and wait for a signal.
41 */ 38 */
@@ -44,51 +41,17 @@ sys_sigsuspend(old_sigset_t mask,
44 unsigned long r5, unsigned long r6, unsigned long r7, 41 unsigned long r5, unsigned long r6, unsigned long r7,
45 struct pt_regs regs) 42 struct pt_regs regs)
46{ 43{
47 sigset_t saveset;
48
49 mask &= _BLOCKABLE; 44 mask &= _BLOCKABLE;
50 spin_lock_irq(&current->sighand->siglock); 45 spin_lock_irq(&current->sighand->siglock);
51 saveset = current->blocked; 46 current->saved_sigmask = current->blocked;
52 siginitset(&current->blocked, mask); 47 siginitset(&current->blocked, mask);
53 recalc_sigpending(); 48 recalc_sigpending();
54 spin_unlock_irq(&current->sighand->siglock); 49 spin_unlock_irq(&current->sighand->siglock);
55 50
56 regs.regs[0] = -EINTR; 51 current->state = TASK_INTERRUPTIBLE;
57 while (1) { 52 schedule();
58 current->state = TASK_INTERRUPTIBLE; 53 set_thread_flag(TIF_RESTORE_SIGMASK);
59 schedule(); 54 return -ERESTARTNOHAND;
60 if (do_signal(&regs, &saveset, regs.regs[0]))
61 return -EINTR;
62 }
63}
64
65asmlinkage int
66sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
67 unsigned long r6, unsigned long r7,
68 struct pt_regs regs)
69{
70 sigset_t saveset, newset;
71
72 /* XXX: Don't preclude handling different sized sigset_t's. */
73 if (sigsetsize != sizeof(sigset_t))
74 return -EINVAL;
75
76 if (copy_from_user(&newset, unewset, sizeof(newset)))
77 return -EFAULT;
78 sigdelsetmask(&newset, ~_BLOCKABLE);
79 spin_lock_irq(&current->sighand->siglock);
80 saveset = current->blocked;
81 current->blocked = newset;
82 recalc_sigpending();
83 spin_unlock_irq(&current->sighand->siglock);
84
85 regs.regs[0] = -EINTR;
86 while (1) {
87 current->state = TASK_INTERRUPTIBLE;
88 schedule();
89 if (do_signal(&regs, &saveset, regs.regs[0]))
90 return -EINTR;
91 }
92} 55}
93 56
94asmlinkage int 57asmlinkage int
@@ -349,7 +312,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
349 return (void __user *)((sp - frame_size) & -8ul); 312 return (void __user *)((sp - frame_size) & -8ul);
350} 313}
351 314
352static void setup_frame(int sig, struct k_sigaction *ka, 315static int setup_frame(int sig, struct k_sigaction *ka,
353 sigset_t *set, struct pt_regs *regs) 316 sigset_t *set, struct pt_regs *regs)
354{ 317{
355 struct sigframe __user *frame; 318 struct sigframe __user *frame;
@@ -369,10 +332,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
369 332
370 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); 333 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
371 334
372 if (_NSIG_WORDS > 1) { 335 if (_NSIG_WORDS > 1)
373 err |= __copy_to_user(frame->extramask, &set->sig[1], 336 err |= __copy_to_user(frame->extramask, &set->sig[1],
374 sizeof(frame->extramask)); 337 sizeof(frame->extramask));
375 }
376 338
377 /* Set up to return from userspace. If provided, use a stub 339 /* Set up to return from userspace. If provided, use a stub
378 already in userspace. */ 340 already in userspace. */
@@ -403,21 +365,22 @@ static void setup_frame(int sig, struct k_sigaction *ka,
403 365
404 set_fs(USER_DS); 366 set_fs(USER_DS);
405 367
406#if DEBUG_SIG 368 pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
407 printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", 369 current->comm, current->pid, frame, regs->pc, regs->pr);
408 current->comm, current->pid, frame, regs->pc, regs->pr);
409#endif
410 370
411 flush_cache_sigtramp(regs->pr); 371 flush_cache_sigtramp(regs->pr);
372
412 if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) 373 if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
413 flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); 374 flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
414 return; 375
376 return 0;
415 377
416give_sigsegv: 378give_sigsegv:
417 force_sigsegv(sig, current); 379 force_sigsegv(sig, current);
380 return -EFAULT;
418} 381}
419 382
420static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 383static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
421 sigset_t *set, struct pt_regs *regs) 384 sigset_t *set, struct pt_regs *regs)
422{ 385{
423 struct rt_sigframe __user *frame; 386 struct rt_sigframe __user *frame;
@@ -478,28 +441,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
478 441
479 set_fs(USER_DS); 442 set_fs(USER_DS);
480 443
481#if DEBUG_SIG 444 pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
482 printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", 445 current->comm, current->pid, frame, regs->pc, regs->pr);
483 current->comm, current->pid, frame, regs->pc, regs->pr);
484#endif
485 446
486 flush_cache_sigtramp(regs->pr); 447 flush_cache_sigtramp(regs->pr);
448
487 if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) 449 if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
488 flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); 450 flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
489 return; 451
452 return 0;
490 453
491give_sigsegv: 454give_sigsegv:
492 force_sigsegv(sig, current); 455 force_sigsegv(sig, current);
456 return -EFAULT;
493} 457}
494 458
495/* 459/*
496 * OK, we're invoking a handler 460 * OK, we're invoking a handler
497 */ 461 */
498 462
499static void 463static int
500handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, 464handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
501 sigset_t *oldset, struct pt_regs *regs) 465 sigset_t *oldset, struct pt_regs *regs)
502{ 466{
467 int ret;
468
503 /* Are we from a system call? */ 469 /* Are we from a system call? */
504 if (regs->tra >= 0) { 470 if (regs->tra >= 0) {
505 /* If so, check system call restarting.. */ 471 /* If so, check system call restarting.. */
@@ -540,19 +506,23 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
540 506
541 /* Set up the stack frame */ 507 /* Set up the stack frame */
542 if (ka->sa.sa_flags & SA_SIGINFO) 508 if (ka->sa.sa_flags & SA_SIGINFO)
543 setup_rt_frame(sig, ka, info, oldset, regs); 509 ret = setup_rt_frame(sig, ka, info, oldset, regs);
544 else 510 else
545 setup_frame(sig, ka, oldset, regs); 511 ret = setup_frame(sig, ka, oldset, regs);
546 512
547 if (ka->sa.sa_flags & SA_ONESHOT) 513 if (ka->sa.sa_flags & SA_ONESHOT)
548 ka->sa.sa_handler = SIG_DFL; 514 ka->sa.sa_handler = SIG_DFL;
549 515
550 spin_lock_irq(&current->sighand->siglock); 516 if (ret == 0) {
551 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); 517 spin_lock_irq(&current->sighand->siglock);
552 if (!(ka->sa.sa_flags & SA_NODEFER)) 518 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
553 sigaddset(&current->blocked,sig); 519 if (!(ka->sa.sa_flags & SA_NODEFER))
554 recalc_sigpending(); 520 sigaddset(&current->blocked,sig);
555 spin_unlock_irq(&current->sighand->siglock); 521 recalc_sigpending();
522 spin_unlock_irq(&current->sighand->siglock);
523 }
524
525 return ret;
556} 526}
557 527
558/* 528/*
@@ -564,11 +534,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
564 * the kernel can handle, and then we build all the user-level signal handling 534 * the kernel can handle, and then we build all the user-level signal handling
565 * stack-frames in one go after that. 535 * stack-frames in one go after that.
566 */ 536 */
567int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0) 537static void do_signal(struct pt_regs *regs, unsigned int save_r0)
568{ 538{
569 siginfo_t info; 539 siginfo_t info;
570 int signr; 540 int signr;
571 struct k_sigaction ka; 541 struct k_sigaction ka;
542 sigset_t *oldset;
572 543
573 /* 544 /*
574 * We want the common case to go fast, which 545 * We want the common case to go fast, which
@@ -577,19 +548,27 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0)
577 * if so. 548 * if so.
578 */ 549 */
579 if (!user_mode(regs)) 550 if (!user_mode(regs))
580 return 1; 551 return;
581 552
582 if (try_to_freeze()) 553 if (try_to_freeze())
583 goto no_signal; 554 goto no_signal;
584 555
585 if (!oldset) 556 if (test_thread_flag(TIF_RESTORE_SIGMASK))
557 oldset = &current->saved_sigmask;
558 else
586 oldset = &current->blocked; 559 oldset = &current->blocked;
587 560
588 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 561 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
589 if (signr > 0) { 562 if (signr > 0) {
590 /* Whee! Actually deliver the signal. */ 563 /* Whee! Actually deliver the signal. */
591 handle_signal(signr, &ka, &info, oldset, regs); 564 if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
592 return 1; 565 /* a signal was successfully delivered; the saved
566 * sigmask will have been stored in the signal frame,
567 * and will be restored by sigreturn, so we can simply
568 * clear the TIF_RESTORE_SIGMASK flag */
569 if (test_thread_flag(TIF_RESTORE_SIGMASK))
570 clear_thread_flag(TIF_RESTORE_SIGMASK);
571 }
593 } 572 }
594 573
595 no_signal: 574 no_signal:
@@ -606,5 +585,19 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0)
606 regs->regs[3] = __NR_restart_syscall; 585 regs->regs[3] = __NR_restart_syscall;
607 } 586 }
608 } 587 }
609 return 0; 588
589 /* if there's no signal to deliver, we just put the saved sigmask
590 * back */
591 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
592 clear_thread_flag(TIF_RESTORE_SIGMASK);
593 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
594 }
595}
596
597asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
598 __u32 thread_info_flags)
599{
600 /* deal with pending signal delivery */
601 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
602 do_signal(regs, save_r0);
610} 603}
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
index ea23b213c77f..768334e95075 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls.S
@@ -319,34 +319,35 @@ ENTRY(sys_call_table)
319 .long sys_mq_getsetattr 319 .long sys_mq_getsetattr
320 .long sys_kexec_load 320 .long sys_kexec_load
321 .long sys_waitid 321 .long sys_waitid
322 .long sys_add_key /* 285 */ 322 .long sys_ni_syscall /* 285 */
323 .long sys_add_key
323 .long sys_request_key 324 .long sys_request_key
324 .long sys_keyctl 325 .long sys_keyctl
325 .long sys_ioprio_set 326 .long sys_ioprio_set
326 .long sys_ioprio_get 327 .long sys_ioprio_get /* 290 */
327 .long sys_inotify_init /* 290 */ 328 .long sys_inotify_init
328 .long sys_inotify_add_watch 329 .long sys_inotify_add_watch
329 .long sys_inotify_rm_watch 330 .long sys_inotify_rm_watch
330 .long sys_migrate_pages 331 .long sys_migrate_pages
331 .long sys_openat 332 .long sys_openat /* 295 */
332 .long sys_mkdirat /* 295 */ 333 .long sys_mkdirat
333 .long sys_mknodat 334 .long sys_mknodat
334 .long sys_fchownat 335 .long sys_fchownat
335 .long sys_futimesat 336 .long sys_futimesat
336 .long sys_fstatat64 337 .long sys_fstatat64 /* 300 */
337 .long sys_unlinkat /* 300 */ 338 .long sys_unlinkat
338 .long sys_renameat 339 .long sys_renameat
339 .long sys_linkat 340 .long sys_linkat
340 .long sys_symlinkat 341 .long sys_symlinkat
341 .long sys_readlinkat 342 .long sys_readlinkat /* 305 */
342 .long sys_fchmodat /* 305 */ 343 .long sys_fchmodat
343 .long sys_faccessat 344 .long sys_faccessat
344 .long sys_ni_syscall /* Reserved for pselect6 */ 345 .long sys_pselect6
345 .long sys_ni_syscall /* Reserved for ppoll */ 346 .long sys_ppoll
346 .long sys_unshare 347 .long sys_unshare /* 310 */
347 .long sys_set_robust_list /* 310 */ 348 .long sys_set_robust_list
348 .long sys_get_robust_list 349 .long sys_get_robust_list
349 .long sys_splice 350 .long sys_splice
350 .long sys_sync_file_range 351 .long sys_sync_file_range
351 .long sys_tee 352 .long sys_tee /* 315 */
352 .long sys_vmsplice /* 315 */ 353 .long sys_vmsplice