diff options
Diffstat (limited to 'arch/sh/kernel/signal_32.c')
-rw-r--r-- | arch/sh/kernel/signal_32.c | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index f311551d9a05..4bbbde895a53 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
@@ -33,6 +33,11 @@ | |||
33 | 33 | ||
34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
35 | 35 | ||
36 | struct fdpic_func_descriptor { | ||
37 | unsigned long text; | ||
38 | unsigned long GOT; | ||
39 | }; | ||
40 | |||
36 | /* | 41 | /* |
37 | * Atomically swap in the new signal mask, and wait for a signal. | 42 | * Atomically swap in the new signal mask, and wait for a signal. |
38 | */ | 43 | */ |
@@ -368,6 +373,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
368 | err |= __put_user(OR_R0_R0, &frame->retcode[6]); | 373 | err |= __put_user(OR_R0_R0, &frame->retcode[6]); |
369 | err |= __put_user((__NR_sigreturn), &frame->retcode[7]); | 374 | err |= __put_user((__NR_sigreturn), &frame->retcode[7]); |
370 | regs->pr = (unsigned long) frame->retcode; | 375 | regs->pr = (unsigned long) frame->retcode; |
376 | flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode)); | ||
371 | } | 377 | } |
372 | 378 | ||
373 | if (err) | 379 | if (err) |
@@ -378,18 +384,21 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
378 | regs->regs[4] = signal; /* Arg for signal handler */ | 384 | regs->regs[4] = signal; /* Arg for signal handler */ |
379 | regs->regs[5] = 0; | 385 | regs->regs[5] = 0; |
380 | regs->regs[6] = (unsigned long) &frame->sc; | 386 | regs->regs[6] = (unsigned long) &frame->sc; |
381 | regs->pc = (unsigned long) ka->sa.sa_handler; | 387 | |
388 | if (current->personality & FDPIC_FUNCPTRS) { | ||
389 | struct fdpic_func_descriptor __user *funcptr = | ||
390 | (struct fdpic_func_descriptor __user *)ka->sa.sa_handler; | ||
391 | |||
392 | __get_user(regs->pc, &funcptr->text); | ||
393 | __get_user(regs->regs[12], &funcptr->GOT); | ||
394 | } else | ||
395 | regs->pc = (unsigned long)ka->sa.sa_handler; | ||
382 | 396 | ||
383 | set_fs(USER_DS); | 397 | set_fs(USER_DS); |
384 | 398 | ||
385 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 399 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
386 | current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); | 400 | current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); |
387 | 401 | ||
388 | flush_cache_sigtramp(regs->pr); | ||
389 | |||
390 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) | ||
391 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); | ||
392 | |||
393 | return 0; | 402 | return 0; |
394 | 403 | ||
395 | give_sigsegv: | 404 | give_sigsegv: |
@@ -458,17 +467,22 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
458 | regs->regs[4] = signal; /* Arg for signal handler */ | 467 | regs->regs[4] = signal; /* Arg for signal handler */ |
459 | regs->regs[5] = (unsigned long) &frame->info; | 468 | regs->regs[5] = (unsigned long) &frame->info; |
460 | regs->regs[6] = (unsigned long) &frame->uc; | 469 | regs->regs[6] = (unsigned long) &frame->uc; |
461 | regs->pc = (unsigned long) ka->sa.sa_handler; | 470 | |
471 | if (current->personality & FDPIC_FUNCPTRS) { | ||
472 | struct fdpic_func_descriptor __user *funcptr = | ||
473 | (struct fdpic_func_descriptor __user *)ka->sa.sa_handler; | ||
474 | |||
475 | __get_user(regs->pc, &funcptr->text); | ||
476 | __get_user(regs->regs[12], &funcptr->GOT); | ||
477 | } else | ||
478 | regs->pc = (unsigned long)ka->sa.sa_handler; | ||
462 | 479 | ||
463 | set_fs(USER_DS); | 480 | set_fs(USER_DS); |
464 | 481 | ||
465 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 482 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
466 | current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); | 483 | current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); |
467 | 484 | ||
468 | flush_cache_sigtramp(regs->pr); | 485 | flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode)); |
469 | |||
470 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) | ||
471 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); | ||
472 | 486 | ||
473 | return 0; | 487 | return 0; |
474 | 488 | ||