Commit 03a347558749caaab482f34410ae5d27e893db89

Authored by Aurelien Jacquiot
Committed by Mark Salter
1 parent 687b12baec

C6X: signal management

Original port to early 2.6 kernel using TI COFF toolchain.
Brought up to date by Mark Salter <msalter@redhat.com>

Signed-off-by: Aurelien Jacquiot <a-jacquiot@ti.com>
Signed-off-by: Mark Salter <msalter@redhat.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>

Showing 3 changed files with 474 additions and 0 deletions Side-by-side Diff

arch/c6x/include/asm/sigcontext.h
  1 +/*
  2 + * Port on Texas Instruments TMS320C6x architecture
  3 + *
  4 + * Copyright (C) 2004, 2009 Texas Instruments Incorporated
  5 + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License version 2 as
  9 + * published by the Free Software Foundation.
  10 + */
  11 +#ifndef _ASM_C6X_SIGCONTEXT_H
  12 +#define _ASM_C6X_SIGCONTEXT_H
  13 +
  14 +
  15 +struct sigcontext {
  16 + unsigned long sc_mask; /* old sigmask */
  17 + unsigned long sc_sp; /* old user stack pointer */
  18 +
  19 + unsigned long sc_a4;
  20 + unsigned long sc_b4;
  21 + unsigned long sc_a6;
  22 + unsigned long sc_b6;
  23 + unsigned long sc_a8;
  24 + unsigned long sc_b8;
  25 +
  26 + unsigned long sc_a0;
  27 + unsigned long sc_a1;
  28 + unsigned long sc_a2;
  29 + unsigned long sc_a3;
  30 + unsigned long sc_a5;
  31 + unsigned long sc_a7;
  32 + unsigned long sc_a9;
  33 +
  34 + unsigned long sc_b0;
  35 + unsigned long sc_b1;
  36 + unsigned long sc_b2;
  37 + unsigned long sc_b3;
  38 + unsigned long sc_b5;
  39 + unsigned long sc_b7;
  40 + unsigned long sc_b9;
  41 +
  42 + unsigned long sc_a16;
  43 + unsigned long sc_a17;
  44 + unsigned long sc_a18;
  45 + unsigned long sc_a19;
  46 + unsigned long sc_a20;
  47 + unsigned long sc_a21;
  48 + unsigned long sc_a22;
  49 + unsigned long sc_a23;
  50 + unsigned long sc_a24;
  51 + unsigned long sc_a25;
  52 + unsigned long sc_a26;
  53 + unsigned long sc_a27;
  54 + unsigned long sc_a28;
  55 + unsigned long sc_a29;
  56 + unsigned long sc_a30;
  57 + unsigned long sc_a31;
  58 +
  59 + unsigned long sc_b16;
  60 + unsigned long sc_b17;
  61 + unsigned long sc_b18;
  62 + unsigned long sc_b19;
  63 + unsigned long sc_b20;
  64 + unsigned long sc_b21;
  65 + unsigned long sc_b22;
  66 + unsigned long sc_b23;
  67 + unsigned long sc_b24;
  68 + unsigned long sc_b25;
  69 + unsigned long sc_b26;
  70 + unsigned long sc_b27;
  71 + unsigned long sc_b28;
  72 + unsigned long sc_b29;
  73 + unsigned long sc_b30;
  74 + unsigned long sc_b31;
  75 +
  76 + unsigned long sc_csr;
  77 + unsigned long sc_pc;
  78 +};
  79 +
  80 +#endif /* _ASM_C6X_SIGCONTEXT_H */
arch/c6x/include/asm/signal.h
  1 +#ifndef _ASM_C6X_SIGNAL_H
  2 +#define _ASM_C6X_SIGNAL_H
  3 +
  4 +#include <asm-generic/signal.h>
  5 +
  6 +#ifndef __ASSEMBLY__
  7 +#include <linux/linkage.h>
  8 +
  9 +struct pt_regs;
  10 +
  11 +extern asmlinkage int do_rt_sigreturn(struct pt_regs *regs);
  12 +extern asmlinkage void do_notify_resume(struct pt_regs *regs,
  13 + u32 thread_info_flags,
  14 + int syscall);
  15 +#endif
  16 +
  17 +#endif /* _ASM_C6X_SIGNAL_H */
arch/c6x/kernel/signal.c
  1 +/*
  2 + * Port on Texas Instruments TMS320C6x architecture
  3 + *
  4 + * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
  5 + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
  6 + *
  7 + * Updated for 2.6.34: Mark Salter <msalter@redhat.com>
  8 + *
  9 + * This program is free software; you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License version 2 as
  11 + * published by the Free Software Foundation.
  12 + */
  13 +
  14 +#include <linux/kernel.h>
  15 +#include <linux/uaccess.h>
  16 +#include <linux/syscalls.h>
  17 +#include <linux/tracehook.h>
  18 +
  19 +#include <asm/ucontext.h>
  20 +#include <asm/cacheflush.h>
  21 +
  22 +
  23 +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
  24 +
  25 +/*
  26 + * Do a signal return, undo the signal stack.
  27 + */
  28 +
  29 +#define RETCODE_SIZE (9 << 2) /* 9 instructions = 36 bytes */
  30 +
  31 +struct rt_sigframe {
  32 + struct siginfo __user *pinfo;
  33 + void __user *puc;
  34 + struct siginfo info;
  35 + struct ucontext uc;
  36 + unsigned long retcode[RETCODE_SIZE >> 2];
  37 +};
  38 +
  39 +static int restore_sigcontext(struct pt_regs *regs,
  40 + struct sigcontext __user *sc)
  41 +{
  42 + int err = 0;
  43 +
  44 + /* The access_ok check was done by caller, so use __get_user here */
  45 +#define COPY(x) (err |= __get_user(regs->x, &sc->sc_##x))
  46 +
  47 + COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
  48 + COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
  49 + COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
  50 +
  51 + COPY(a16); COPY(a17); COPY(a18); COPY(a19);
  52 + COPY(a20); COPY(a21); COPY(a22); COPY(a23);
  53 + COPY(a24); COPY(a25); COPY(a26); COPY(a27);
  54 + COPY(a28); COPY(a29); COPY(a30); COPY(a31);
  55 + COPY(b16); COPY(b17); COPY(b18); COPY(b19);
  56 + COPY(b20); COPY(b21); COPY(b22); COPY(b23);
  57 + COPY(b24); COPY(b25); COPY(b26); COPY(b27);
  58 + COPY(b28); COPY(b29); COPY(b30); COPY(b31);
  59 +
  60 + COPY(csr); COPY(pc);
  61 +
  62 +#undef COPY
  63 +
  64 + return err;
  65 +}
  66 +
  67 +asmlinkage int do_rt_sigreturn(struct pt_regs *regs)
  68 +{
  69 + struct rt_sigframe __user *frame;
  70 + sigset_t set;
  71 +
  72 + /*
  73 + * Since we stacked the signal on a dword boundary,
  74 + * 'sp' should be dword aligned here. If it's
  75 + * not, then the user is trying to mess with us.
  76 + */
  77 + if (regs->sp & 7)
  78 + goto badframe;
  79 +
  80 + frame = (struct rt_sigframe __user *) ((unsigned long) regs->sp + 8);
  81 +
  82 + if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
  83 + goto badframe;
  84 + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
  85 + goto badframe;
  86 +
  87 + sigdelsetmask(&set, ~_BLOCKABLE);
  88 + spin_lock_irq(&current->sighand->siglock);
  89 + current->blocked = set;
  90 + recalc_sigpending();
  91 + spin_unlock_irq(&current->sighand->siglock);
  92 +
  93 + if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
  94 + goto badframe;
  95 +
  96 + return regs->a4;
  97 +
  98 +badframe:
  99 + force_sig(SIGSEGV, current);
  100 + return 0;
  101 +}
  102 +
  103 +static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
  104 + unsigned long mask)
  105 +{
  106 + int err = 0;
  107 +
  108 + err |= __put_user(mask, &sc->sc_mask);
  109 +
  110 + /* The access_ok check was done by caller, so use __put_user here */
  111 +#define COPY(x) (err |= __put_user(regs->x, &sc->sc_##x))
  112 +
  113 + COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
  114 + COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
  115 + COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
  116 +
  117 + COPY(a16); COPY(a17); COPY(a18); COPY(a19);
  118 + COPY(a20); COPY(a21); COPY(a22); COPY(a23);
  119 + COPY(a24); COPY(a25); COPY(a26); COPY(a27);
  120 + COPY(a28); COPY(a29); COPY(a30); COPY(a31);
  121 + COPY(b16); COPY(b17); COPY(b18); COPY(b19);
  122 + COPY(b20); COPY(b21); COPY(b22); COPY(b23);
  123 + COPY(b24); COPY(b25); COPY(b26); COPY(b27);
  124 + COPY(b28); COPY(b29); COPY(b30); COPY(b31);
  125 +
  126 + COPY(csr); COPY(pc);
  127 +
  128 +#undef COPY
  129 +
  130 + return err;
  131 +}
  132 +
  133 +static inline void __user *get_sigframe(struct k_sigaction *ka,
  134 + struct pt_regs *regs,
  135 + unsigned long framesize)
  136 +{
  137 + unsigned long sp = regs->sp;
  138 +
  139 + /*
  140 + * This is the X/Open sanctioned signal stack switching.
  141 + */
  142 + if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(sp) == 0)
  143 + sp = current->sas_ss_sp + current->sas_ss_size;
  144 +
  145 + /*
  146 + * No matter what happens, 'sp' must be dword
  147 + * aligned. Otherwise, nasty things will happen
  148 + */
  149 + return (void __user *)((sp - framesize) & ~7);
  150 +}
  151 +
  152 +static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
  153 + sigset_t *set, struct pt_regs *regs)
  154 +{
  155 + struct rt_sigframe __user *frame;
  156 + unsigned long __user *retcode;
  157 + int err = 0;
  158 +
  159 + frame = get_sigframe(ka, regs, sizeof(*frame));
  160 +
  161 + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
  162 + goto segv_and_exit;
  163 +
  164 + err |= __put_user(&frame->info, &frame->pinfo);
  165 + err |= __put_user(&frame->uc, &frame->puc);
  166 + err |= copy_siginfo_to_user(&frame->info, info);
  167 +
  168 + /* Clear all the bits of the ucontext we don't use. */
  169 + err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
  170 +
  171 + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
  172 + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
  173 +
  174 + /* Set up to return from userspace */
  175 + retcode = (unsigned long __user *) &frame->retcode;
  176 +
  177 + /* The access_ok check was done above, so use __put_user here */
  178 +#define COPY(x) (err |= __put_user(x, retcode++))
  179 +
  180 + COPY(0x0000002AUL | (__NR_rt_sigreturn << 7));
  181 + /* MVK __NR_rt_sigreturn,B0 */
  182 + COPY(0x10000000UL); /* SWE */
  183 + COPY(0x00006000UL); /* NOP 4 */
  184 + COPY(0x00006000UL); /* NOP 4 */
  185 + COPY(0x00006000UL); /* NOP 4 */
  186 + COPY(0x00006000UL); /* NOP 4 */
  187 + COPY(0x00006000UL); /* NOP 4 */
  188 + COPY(0x00006000UL); /* NOP 4 */
  189 + COPY(0x00006000UL); /* NOP 4 */
  190 +
  191 +#undef COPY
  192 +
  193 + if (err)
  194 + goto segv_and_exit;
  195 +
  196 + flush_icache_range((unsigned long) &frame->retcode,
  197 + (unsigned long) &frame->retcode + RETCODE_SIZE);
  198 +
  199 + retcode = (unsigned long __user *) &frame->retcode;
  200 +
  201 + /* Change user context to branch to signal handler */
  202 + regs->sp = (unsigned long) frame - 8;
  203 + regs->b3 = (unsigned long) retcode;
  204 + regs->pc = (unsigned long) ka->sa.sa_handler;
  205 +
  206 + /* Give the signal number to the handler */
  207 + regs->a4 = signr;
  208 +
  209 + /*
  210 + * For realtime signals we must also set the second and third
  211 + * arguments for the signal handler.
  212 + * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
  213 + */
  214 + regs->b4 = (unsigned long)&frame->info;
  215 + regs->a6 = (unsigned long)&frame->uc;
  216 +
  217 + return 0;
  218 +
  219 +segv_and_exit:
  220 + force_sigsegv(signr, current);
  221 + return -EFAULT;
  222 +}
  223 +
  224 +static inline void
  225 +handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
  226 +{
  227 + switch (regs->a4) {
  228 + case -ERESTARTNOHAND:
  229 + if (!has_handler)
  230 + goto do_restart;
  231 + regs->a4 = -EINTR;
  232 + break;
  233 +
  234 + case -ERESTARTSYS:
  235 + if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
  236 + regs->a4 = -EINTR;
  237 + break;
  238 + }
  239 + /* fallthrough */
  240 + case -ERESTARTNOINTR:
  241 +do_restart:
  242 + regs->a4 = regs->orig_a4;
  243 + regs->pc -= 4;
  244 + break;
  245 + }
  246 +}
  247 +
  248 +/*
  249 + * handle the actual delivery of a signal to userspace
  250 + */
  251 +static int handle_signal(int sig,
  252 + siginfo_t *info, struct k_sigaction *ka,
  253 + sigset_t *oldset, struct pt_regs *regs,
  254 + int syscall)
  255 +{
  256 + int ret;
  257 +
  258 + /* Are we from a system call? */
  259 + if (syscall) {
  260 + /* If so, check system call restarting.. */
  261 + switch (regs->a4) {
  262 + case -ERESTART_RESTARTBLOCK:
  263 + case -ERESTARTNOHAND:
  264 + regs->a4 = -EINTR;
  265 + break;
  266 +
  267 + case -ERESTARTSYS:
  268 + if (!(ka->sa.sa_flags & SA_RESTART)) {
  269 + regs->a4 = -EINTR;
  270 + break;
  271 + }
  272 +
  273 + /* fallthrough */
  274 + case -ERESTARTNOINTR:
  275 + regs->a4 = regs->orig_a4;
  276 + regs->pc -= 4;
  277 + }
  278 + }
  279 +
  280 + /* Set up the stack frame */
  281 + ret = setup_rt_frame(sig, ka, info, oldset, regs);
  282 + if (ret == 0) {
  283 + spin_lock_irq(&current->sighand->siglock);
  284 + sigorsets(&current->blocked, &current->blocked,
  285 + &ka->sa.sa_mask);
  286 + if (!(ka->sa.sa_flags & SA_NODEFER))
  287 + sigaddset(&current->blocked, sig);
  288 + recalc_sigpending();
  289 + spin_unlock_irq(&current->sighand->siglock);
  290 + }
  291 +
  292 + return ret;
  293 +}
  294 +
  295 +/*
  296 + * handle a potential signal
  297 + */
  298 +static void do_signal(struct pt_regs *regs, int syscall)
  299 +{
  300 + struct k_sigaction ka;
  301 + siginfo_t info;
  302 + sigset_t *oldset;
  303 + int signr;
  304 +
  305 + /* we want the common case to go fast, which is why we may in certain
  306 + * cases get here from kernel mode */
  307 + if (!user_mode(regs))
  308 + return;
  309 +
  310 + if (test_thread_flag(TIF_RESTORE_SIGMASK))
  311 + oldset = &current->saved_sigmask;
  312 + else
  313 + oldset = &current->blocked;
  314 +
  315 + signr = get_signal_to_deliver(&info, &ka, regs, NULL);
  316 + if (signr > 0) {
  317 + if (handle_signal(signr, &info, &ka, oldset,
  318 + regs, syscall) == 0) {
  319 + /* a signal was successfully delivered; the saved
  320 + * sigmask will have been stored in the signal frame,
  321 + * and will be restored by sigreturn, so we can simply
  322 + * clear the TIF_RESTORE_SIGMASK flag */
  323 + if (test_thread_flag(TIF_RESTORE_SIGMASK))
  324 + clear_thread_flag(TIF_RESTORE_SIGMASK);
  325 +
  326 + tracehook_signal_handler(signr, &info, &ka, regs, 0);
  327 + }
  328 +
  329 + return;
  330 + }
  331 +
  332 + /* did we come from a system call? */
  333 + if (syscall) {
  334 + /* restart the system call - no handlers present */
  335 + switch (regs->a4) {
  336 + case -ERESTARTNOHAND:
  337 + case -ERESTARTSYS:
  338 + case -ERESTARTNOINTR:
  339 + regs->a4 = regs->orig_a4;
  340 + regs->pc -= 4;
  341 + break;
  342 +
  343 + case -ERESTART_RESTARTBLOCK:
  344 + regs->a4 = regs->orig_a4;
  345 + regs->b0 = __NR_restart_syscall;
  346 + regs->pc -= 4;
  347 + break;
  348 + }
  349 + }
  350 +
  351 + /* if there's no signal to deliver, we just put the saved sigmask
  352 + * back */
  353 + if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
  354 + clear_thread_flag(TIF_RESTORE_SIGMASK);
  355 + sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
  356 + }
  357 +}
  358 +
  359 +/*
  360 + * notification of userspace execution resumption
  361 + * - triggered by current->work.notify_resume
  362 + */
  363 +asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags,
  364 + int syscall)
  365 +{
  366 + /* deal with pending signal delivery */
  367 + if (thread_info_flags & ((1 << TIF_SIGPENDING) |
  368 + (1 << TIF_RESTORE_SIGMASK)))
  369 + do_signal(regs, syscall);
  370 +
  371 + if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) {
  372 + clear_thread_flag(TIF_NOTIFY_RESUME);
  373 + tracehook_notify_resume(regs);
  374 + if (current->replacement_session_keyring)
  375 + key_replace_session_keyring();
  376 + }
  377 +}