~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/sh/kernel/signal_64.c

Version: ~ [ linux-5.3-rc5 ] ~ [ linux-5.2.9 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.67 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.139 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.189 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.189 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.72 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * arch/sh/kernel/signal_64.c
  3  *
  4  * Copyright (C) 2000, 2001  Paolo Alberelli
  5  * Copyright (C) 2003 - 2008  Paul Mundt
  6  * Copyright (C) 2004  Richard Curnow
  7  *
  8  * This file is subject to the terms and conditions of the GNU General Public
  9  * License.  See the file "COPYING" in the main directory of this archive
 10  * for more details.
 11  */
 12 #include <linux/rwsem.h>
 13 #include <linux/sched.h>
 14 #include <linux/mm.h>
 15 #include <linux/smp.h>
 16 #include <linux/kernel.h>
 17 #include <linux/signal.h>
 18 #include <linux/errno.h>
 19 #include <linux/wait.h>
 20 #include <linux/personality.h>
 21 #include <linux/freezer.h>
 22 #include <linux/ptrace.h>
 23 #include <linux/unistd.h>
 24 #include <linux/stddef.h>
 25 #include <linux/tracehook.h>
 26 #include <asm/ucontext.h>
 27 #include <asm/uaccess.h>
 28 #include <asm/pgtable.h>
 29 #include <asm/cacheflush.h>
 30 #include <asm/fpu.h>
 31 
 32 #define REG_RET 9
 33 #define REG_ARG1 2
 34 #define REG_ARG2 3
 35 #define REG_ARG3 4
 36 #define REG_SP 15
 37 #define REG_PR 18
 38 #define REF_REG_RET regs->regs[REG_RET]
 39 #define REF_REG_SP regs->regs[REG_SP]
 40 #define DEREF_REG_PR regs->regs[REG_PR]
 41 
 42 #define DEBUG_SIG 0
 43 
 44 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 45 
 46 static int
 47 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 48                 sigset_t *oldset, struct pt_regs * regs);
 49 
 50 static inline void
 51 handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa)
 52 {
 53         /* If we're not from a syscall, bail out */
 54         if (regs->syscall_nr < 0)
 55                 return;
 56 
 57         /* check for system call restart.. */
 58         switch (regs->regs[REG_RET]) {
 59                 case -ERESTART_RESTARTBLOCK:
 60                 case -ERESTARTNOHAND:
 61                 no_system_call_restart:
 62                         regs->regs[REG_RET] = -EINTR;
 63                         break;
 64 
 65                 case -ERESTARTSYS:
 66                         if (!(sa->sa_flags & SA_RESTART))
 67                                 goto no_system_call_restart;
 68                 /* fallthrough */
 69                 case -ERESTARTNOINTR:
 70                         /* Decode syscall # */
 71                         regs->regs[REG_RET] = regs->syscall_nr;
 72                         regs->pc -= 4;
 73                         break;
 74         }
 75 }
 76 
 77 /*
 78  * Note that 'init' is a special process: it doesn't get signals it doesn't
 79  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 80  * mistake.
 81  *
 82  * Note that we go through the signals twice: once to check the signals that
 83  * the kernel can handle, and then we build all the user-level signal handling
 84  * stack-frames in one go after that.
 85  */
 86 static int do_signal(struct pt_regs *regs, sigset_t *oldset)
 87 {
 88         siginfo_t info;
 89         int signr;
 90         struct k_sigaction ka;
 91 
 92         /*
 93          * We want the common case to go fast, which
 94          * is why we may in certain cases get here from
 95          * kernel mode. Just return without doing anything
 96          * if so.
 97          */
 98         if (!user_mode(regs))
 99                 return 1;
100 
101         if (current_thread_info()->status & TS_RESTORE_SIGMASK)
102                 oldset = &current->saved_sigmask;
103         else if (!oldset)
104                 oldset = &current->blocked;
105 
106         signr = get_signal_to_deliver(&info, &ka, regs, 0);
107         if (signr > 0) {
108                 handle_syscall_restart(regs, &ka.sa);
109 
110                 /* Whee!  Actually deliver the signal.  */
111                 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
112                         /*
113                          * If a signal was successfully delivered, the
114                          * saved sigmask is in its frame, and we can
115                          * clear the TS_RESTORE_SIGMASK flag.
116                          */
117                         current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
118 
119                         tracehook_signal_handler(signr, &info, &ka, regs,
120                                         test_thread_flag(TIF_SINGLESTEP));
121                         return 1;
122                 }
123         }
124 
125         /* Did we come from a system call? */
126         if (regs->syscall_nr >= 0) {
127                 /* Restart the system call - no handlers present */
128                 switch (regs->regs[REG_RET]) {
129                 case -ERESTARTNOHAND:
130                 case -ERESTARTSYS:
131                 case -ERESTARTNOINTR:
132                         /* Decode Syscall # */
133                         regs->regs[REG_RET] = regs->syscall_nr;
134                         regs->pc -= 4;
135                         break;
136 
137                 case -ERESTART_RESTARTBLOCK:
138                         regs->regs[REG_RET] = __NR_restart_syscall;
139                         regs->pc -= 4;
140                         break;
141                 }
142         }
143 
144         /* No signal to deliver -- put the saved sigmask back */
145         if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
146                 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
147                 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
148         }
149 
150         return 0;
151 }
152 
153 /*
154  * Atomically swap in the new signal mask, and wait for a signal.
155  */
156 asmlinkage int
157 sys_sigsuspend(old_sigset_t mask,
158                unsigned long r3, unsigned long r4, unsigned long r5,
159                unsigned long r6, unsigned long r7,
160                struct pt_regs * regs)
161 {
162         sigset_t saveset, blocked;
163 
164         saveset = current->blocked;
165 
166         mask &= _BLOCKABLE;
167         siginitset(&blocked, mask);
168         set_current_blocked(&blocked);
169 
170         REF_REG_RET = -EINTR;
171         while (1) {
172                 current->state = TASK_INTERRUPTIBLE;
173                 schedule();
174                 set_restore_sigmask();
175                 regs->pc += 4;    /* because sys_sigreturn decrements the pc */
176                 if (do_signal(regs, &saveset)) {
177                         /* pc now points at signal handler. Need to decrement
178                            it because entry.S will increment it. */
179                         regs->pc -= 4;
180                         return -EINTR;
181                 }
182         }
183 }
184 
185 asmlinkage int
186 sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
187                   unsigned long r4, unsigned long r5, unsigned long r6,
188                   unsigned long r7,
189                   struct pt_regs * regs)
190 {
191         sigset_t saveset, newset;
192 
193         /* XXX: Don't preclude handling different sized sigset_t's.  */
194         if (sigsetsize != sizeof(sigset_t))
195                 return -EINVAL;
196 
197         if (copy_from_user(&newset, unewset, sizeof(newset)))
198                 return -EFAULT;
199         sigdelsetmask(&newset, ~_BLOCKABLE);
200         saveset = current->blocked;
201         set_current_blocked(&newset);
202 
203         REF_REG_RET = -EINTR;
204         while (1) {
205                 current->state = TASK_INTERRUPTIBLE;
206                 schedule();
207                 regs->pc += 4;    /* because sys_sigreturn decrements the pc */
208                 if (do_signal(regs, &saveset)) {
209                         /* pc now points at signal handler. Need to decrement
210                            it because entry.S will increment it. */
211                         regs->pc -= 4;
212                         return -EINTR;
213                 }
214         }
215 }
216 
217 asmlinkage int
218 sys_sigaction(int sig, const struct old_sigaction __user *act,
219               struct old_sigaction __user *oact)
220 {
221         struct k_sigaction new_ka, old_ka;
222         int ret;
223 
224         if (act) {
225                 old_sigset_t mask;
226                 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
227                     __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
228                     __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
229                         return -EFAULT;
230                 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
231                 __get_user(mask, &act->sa_mask);
232                 siginitset(&new_ka.sa.sa_mask, mask);
233         }
234 
235         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
236 
237         if (!ret && oact) {
238                 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
239                     __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
240                     __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
241                         return -EFAULT;
242                 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
243                 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
244         }
245 
246         return ret;
247 }
248 
249 asmlinkage int
250 sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
251                 unsigned long r4, unsigned long r5, unsigned long r6,
252                 unsigned long r7,
253                 struct pt_regs * regs)
254 {
255         return do_sigaltstack(uss, uoss, REF_REG_SP);
256 }
257 
258 /*
259  * Do a signal return; undo the signal stack.
260  */
261 struct sigframe {
262         struct sigcontext sc;
263         unsigned long extramask[_NSIG_WORDS-1];
264         long long retcode[2];
265 };
266 
267 struct rt_sigframe {
268         struct siginfo __user *pinfo;
269         void *puc;
270         struct siginfo info;
271         struct ucontext uc;
272         long long retcode[2];
273 };
274 
275 #ifdef CONFIG_SH_FPU
276 static inline int
277 restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
278 {
279         int err = 0;
280         int fpvalid;
281 
282         err |= __get_user (fpvalid, &sc->sc_fpvalid);
283         conditional_used_math(fpvalid);
284         if (! fpvalid)
285                 return err;
286 
287         if (current == last_task_used_math) {
288                 last_task_used_math = NULL;
289                 regs->sr |= SR_FD;
290         }
291 
292         err |= __copy_from_user(&current->thread.xstate->hardfpu, &sc->sc_fpregs[0],
293                                 (sizeof(long long) * 32) + (sizeof(int) * 1));
294 
295         return err;
296 }
297 
298 static inline int
299 setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
300 {
301         int err = 0;
302         int fpvalid;
303 
304         fpvalid = !!used_math();
305         err |= __put_user(fpvalid, &sc->sc_fpvalid);
306         if (! fpvalid)
307                 return err;
308 
309         if (current == last_task_used_math) {
310                 enable_fpu();
311                 save_fpu(current);
312                 disable_fpu();
313                 last_task_used_math = NULL;
314                 regs->sr |= SR_FD;
315         }
316 
317         err |= __copy_to_user(&sc->sc_fpregs[0], &current->thread.xstate->hardfpu,
318                               (sizeof(long long) * 32) + (sizeof(int) * 1));
319         clear_used_math();
320 
321         return err;
322 }
323 #else
324 static inline int
325 restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
326 {
327         return 0;
328 }
329 static inline int
330 setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
331 {
332         return 0;
333 }
334 #endif
335 
336 static int
337 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p)
338 {
339         unsigned int err = 0;
340         unsigned long long current_sr, new_sr;
341 #define SR_MASK 0xffff8cfd
342 
343 #define COPY(x)         err |= __get_user(regs->x, &sc->sc_##x)
344 
345         COPY(regs[0]);  COPY(regs[1]);  COPY(regs[2]);  COPY(regs[3]);
346         COPY(regs[4]);  COPY(regs[5]);  COPY(regs[6]);  COPY(regs[7]);
347         COPY(regs[8]);  COPY(regs[9]);  COPY(regs[10]); COPY(regs[11]);
348         COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
349         COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
350         COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
351         COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
352         COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
353         COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
354         COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
355         COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
356         COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
357         COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
358         COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
359         COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
360         COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
361         COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
362         COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
363 
364         /* Prevent the signal handler manipulating SR in a way that can
365            crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be
366            modified */
367         current_sr = regs->sr;
368         err |= __get_user(new_sr, &sc->sc_sr);
369         regs->sr &= SR_MASK;
370         regs->sr |= (new_sr & ~SR_MASK);
371 
372         COPY(pc);
373 
374 #undef COPY
375 
376         /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr
377          * has been restored above.) */
378         err |= restore_sigcontext_fpu(regs, sc);
379 
380         regs->syscall_nr = -1;          /* disable syscall checks */
381         err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]);
382         return err;
383 }
384 
385 asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,
386                                    unsigned long r4, unsigned long r5,
387                                    unsigned long r6, unsigned long r7,
388                                    struct pt_regs * regs)
389 {
390         struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP;
391         sigset_t set;
392         long long ret;
393 
394         /* Always make any pending restarted system calls return -EINTR */
395         current_thread_info()->restart_block.fn = do_no_restart_syscall;
396 
397         if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
398                 goto badframe;
399 
400         if (__get_user(set.sig[0], &frame->sc.oldmask)
401             || (_NSIG_WORDS > 1
402                 && __copy_from_user(&set.sig[1], &frame->extramask,
403                                     sizeof(frame->extramask))))
404                 goto badframe;
405 
406         sigdelsetmask(&set, ~_BLOCKABLE);
407         set_current_blocked(&set);
408 
409         if (restore_sigcontext(regs, &frame->sc, &ret))
410                 goto badframe;
411         regs->pc -= 4;
412 
413         return (int) ret;
414 
415 badframe:
416         force_sig(SIGSEGV, current);
417         return 0;
418 }
419 
420 asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
421                                 unsigned long r4, unsigned long r5,
422                                 unsigned long r6, unsigned long r7,
423                                 struct pt_regs * regs)
424 {
425         struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP;
426         sigset_t set;
427         stack_t __user st;
428         long long ret;
429 
430         /* Always make any pending restarted system calls return -EINTR */
431         current_thread_info()->restart_block.fn = do_no_restart_syscall;
432 
433         if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
434                 goto badframe;
435 
436         if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
437                 goto badframe;
438 
439         sigdelsetmask(&set, ~_BLOCKABLE);
440         set_current_blocked(&set);
441 
442         if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
443                 goto badframe;
444         regs->pc -= 4;
445 
446         if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
447                 goto badframe;
448         /* It is more difficult to avoid calling this function than to
449            call it and ignore errors.  */
450         do_sigaltstack(&st, NULL, REF_REG_SP);
451 
452         return (int) ret;
453 
454 badframe:
455         force_sig(SIGSEGV, current);
456         return 0;
457 }
458 
459 /*
460  * Set up a signal frame.
461  */
462 static int
463 setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
464                  unsigned long mask)
465 {
466         int err = 0;
467 
468         /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */
469         err |= setup_sigcontext_fpu(regs, sc);
470 
471 #define COPY(x)         err |= __put_user(regs->x, &sc->sc_##x)
472 
473         COPY(regs[0]);  COPY(regs[1]);  COPY(regs[2]);  COPY(regs[3]);
474         COPY(regs[4]);  COPY(regs[5]);  COPY(regs[6]);  COPY(regs[7]);
475         COPY(regs[8]);  COPY(regs[9]);  COPY(regs[10]); COPY(regs[11]);
476         COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
477         COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
478         COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
479         COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
480         COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
481         COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
482         COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
483         COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
484         COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
485         COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
486         COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
487         COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
488         COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
489         COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
490         COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
491         COPY(sr);       COPY(pc);
492 
493 #undef COPY
494 
495         err |= __put_user(mask, &sc->oldmask);
496 
497         return err;
498 }
499 
500 /*
501  * Determine which stack to use..
502  */
503 static inline void __user *
504 get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
505 {
506         if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
507                 sp = current->sas_ss_sp + current->sas_ss_size;
508 
509         return (void __user *)((sp - frame_size) & -8ul);
510 }
511 
512 void sa_default_restorer(void);         /* See comments below */
513 void sa_default_rt_restorer(void);      /* See comments below */
514 
515 static int setup_frame(int sig, struct k_sigaction *ka,
516                        sigset_t *set, struct pt_regs *regs)
517 {
518         struct sigframe __user *frame;
519         int err = 0;
520         int signal;
521 
522         frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
523 
524         if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
525                 goto give_sigsegv;
526 
527         signal = current_thread_info()->exec_domain
528                 && current_thread_info()->exec_domain->signal_invmap
529                 && sig < 32
530                 ? current_thread_info()->exec_domain->signal_invmap[sig]
531                 : sig;
532 
533         err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
534 
535         /* Give up earlier as i386, in case */
536         if (err)
537                 goto give_sigsegv;
538 
539         if (_NSIG_WORDS > 1) {
540                 err |= __copy_to_user(frame->extramask, &set->sig[1],
541                                       sizeof(frame->extramask)); }
542 
543         /* Give up earlier as i386, in case */
544         if (err)
545                 goto give_sigsegv;
546 
547         /* Set up to return from userspace.  If provided, use a stub
548            already in userspace.  */
549         if (ka->sa.sa_flags & SA_RESTORER) {
550                 /*
551                  * On SH5 all edited pointers are subject to NEFF
552                  */
553                 DEREF_REG_PR = neff_sign_extend((unsigned long)
554                         ka->sa.sa_restorer | 0x1);
555         } else {
556                 /*
557                  * Different approach on SH5.
558                  * . Endianness independent asm code gets placed in entry.S .
559                  *   This is limited to four ASM instructions corresponding
560                  *   to two long longs in size.
561                  * . err checking is done on the else branch only
562                  * . flush_icache_range() is called upon __put_user() only
563                  * . all edited pointers are subject to NEFF
564                  * . being code, linker turns ShMedia bit on, always
565                  *   dereference index -1.
566                  */
567                 DEREF_REG_PR = neff_sign_extend((unsigned long)
568                         frame->retcode | 0x01);
569 
570                 if (__copy_to_user(frame->retcode,
571                         (void *)((unsigned long)sa_default_restorer & (~1)), 16) != 0)
572                         goto give_sigsegv;
573 
574                 /* Cohere the trampoline with the I-cache. */
575                 flush_cache_sigtramp(DEREF_REG_PR-1);
576         }
577 
578         /*
579          * Set up registers for signal handler.
580          * All edited pointers are subject to NEFF.
581          */
582         regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
583         regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
584 
585         /* FIXME:
586            The glibc profiling support for SH-5 needs to be passed a sigcontext
587            so it can retrieve the PC.  At some point during 2003 the glibc
588            support was changed to receive the sigcontext through the 2nd
589            argument, but there are still versions of libc.so in use that use
590            the 3rd argument.  Until libc.so is stabilised, pass the sigcontext
591            through both 2nd and 3rd arguments.
592         */
593 
594         regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
595         regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
596 
597         regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
598 
599         set_fs(USER_DS);
600 
601         /* Broken %016Lx */
602         pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
603                  signal, current->comm, current->pid, frame,
604                  regs->pc >> 32, regs->pc & 0xffffffff,
605                  DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
606 
607         return 0;
608 
609 give_sigsegv:
610         force_sigsegv(sig, current);
611         return -EFAULT;
612 }
613 
614 static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
615                           sigset_t *set, struct pt_regs *regs)
616 {
617         struct rt_sigframe __user *frame;
618         int err = 0;
619         int signal;
620 
621         frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
622 
623         if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
624                 goto give_sigsegv;
625 
626         signal = current_thread_info()->exec_domain
627                 && current_thread_info()->exec_domain->signal_invmap
628                 && sig < 32
629                 ? current_thread_info()->exec_domain->signal_invmap[sig]
630                 : sig;
631 
632         err |= __put_user(&frame->info, &frame->pinfo);
633         err |= __put_user(&frame->uc, &frame->puc);
634         err |= copy_siginfo_to_user(&frame->info, info);
635 
636         /* Give up earlier as i386, in case */
637         if (err)
638                 goto give_sigsegv;
639 
640         /* Create the ucontext.  */
641         err |= __put_user(0, &frame->uc.uc_flags);
642         err |= __put_user(0, &frame->uc.uc_link);
643         err |= __put_user((void *)current->sas_ss_sp,
644                           &frame->uc.uc_stack.ss_sp);
645         err |= __put_user(sas_ss_flags(regs->regs[REG_SP]),
646                           &frame->uc.uc_stack.ss_flags);
647         err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
648         err |= setup_sigcontext(&frame->uc.uc_mcontext,
649                                 regs, set->sig[0]);
650         err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
651 
652         /* Give up earlier as i386, in case */
653         if (err)
654                 goto give_sigsegv;
655 
656         /* Set up to return from userspace.  If provided, use a stub
657            already in userspace.  */
658         if (ka->sa.sa_flags & SA_RESTORER) {
659                 /*
660                  * On SH5 all edited pointers are subject to NEFF
661                  */
662                 DEREF_REG_PR = neff_sign_extend((unsigned long)
663                         ka->sa.sa_restorer | 0x1);
664         } else {
665                 /*
666                  * Different approach on SH5.
667                  * . Endianness independent asm code gets placed in entry.S .
668                  *   This is limited to four ASM instructions corresponding
669                  *   to two long longs in size.
670                  * . err checking is done on the else branch only
671                  * . flush_icache_range() is called upon __put_user() only
672                  * . all edited pointers are subject to NEFF
673                  * . being code, linker turns ShMedia bit on, always
674                  *   dereference index -1.
675                  */
676                 DEREF_REG_PR = neff_sign_extend((unsigned long)
677                         frame->retcode | 0x01);
678 
679                 if (__copy_to_user(frame->retcode,
680                         (void *)((unsigned long)sa_default_rt_restorer & (~1)), 16) != 0)
681                         goto give_sigsegv;
682 
683                 /* Cohere the trampoline with the I-cache. */
684                 flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15);
685         }
686 
687         /*
688          * Set up registers for signal handler.
689          * All edited pointers are subject to NEFF.
690          */
691         regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
692         regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
693         regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info;
694         regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext;
695         regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
696 
697         set_fs(USER_DS);
698 
699         pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
700                  signal, current->comm, current->pid, frame,
701                  regs->pc >> 32, regs->pc & 0xffffffff,
702                  DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
703 
704         return 0;
705 
706 give_sigsegv:
707         force_sigsegv(sig, current);
708         return -EFAULT;
709 }
710 
711 /*
712  * OK, we're invoking a handler
713  */
714 static int
715 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
716                 sigset_t *oldset, struct pt_regs * regs)
717 {
718         int ret;
719 
720         /* Set up the stack frame */
721         if (ka->sa.sa_flags & SA_SIGINFO)
722                 ret = setup_rt_frame(sig, ka, info, oldset, regs);
723         else
724                 ret = setup_frame(sig, ka, oldset, regs);
725 
726         if (ret == 0)
727                 block_sigmask(ka, sig);
728 
729         return ret;
730 }
731 
732 asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
733 {
734         if (thread_info_flags & _TIF_SIGPENDING)
735                 do_signal(regs, 0);
736 
737         if (thread_info_flags & _TIF_NOTIFY_RESUME) {
738                 clear_thread_flag(TIF_NOTIFY_RESUME);
739                 tracehook_notify_resume(regs);
740                 if (current->replacement_session_keyring)
741                         key_replace_session_keyring();
742         }
743 }
744 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp