root/arch/h8300/kernel/signal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. restore_sigcontext
  2. sys_rt_sigreturn
  3. setup_sigcontext
  4. get_sigframe
  5. setup_rt_frame
  6. handle_restart
  7. handle_signal
  8. do_signal
  9. do_notify_resume

   1 /*
   2  *  linux/arch/h8300/kernel/signal.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  *
   6  * This file is subject to the terms and conditions of the GNU General Public
   7  * License.  See the file COPYING in the main directory of this archive
   8  * for more details.
   9  */
  10 
  11 /*
  12  * uClinux H8/300 support by Yoshinori Sato <ysato@users.sourceforge.jp>
  13  *                and David McCullough <davidm@snapgear.com>
  14  *
  15  * Based on
  16  * Linux/m68k by Hamish Macdonald
  17  */
  18 
  19 /*
  20  * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
  21  * Atari :-) Current limitation: Only one sigstack can be active at one time.
  22  * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
  23  * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
  24  * signal handlers!
  25  */
  26 
  27 #include <linux/sched.h>
  28 #include <linux/sched/task_stack.h>
  29 #include <linux/mm.h>
  30 #include <linux/kernel.h>
  31 #include <linux/signal.h>
  32 #include <linux/syscalls.h>
  33 #include <linux/errno.h>
  34 #include <linux/wait.h>
  35 #include <linux/ptrace.h>
  36 #include <linux/unistd.h>
  37 #include <linux/stddef.h>
  38 #include <linux/highuid.h>
  39 #include <linux/personality.h>
  40 #include <linux/tty.h>
  41 #include <linux/binfmts.h>
  42 #include <linux/tracehook.h>
  43 
  44 #include <asm/setup.h>
  45 #include <linux/uaccess.h>
  46 #include <asm/pgtable.h>
  47 #include <asm/traps.h>
  48 #include <asm/ucontext.h>
  49 
  50 /*
  51  * Do a signal return; undo the signal stack.
  52  *
  53  * Keep the return code on the stack quadword aligned!
  54  * That makes the cache flush below easier.
  55  */
  56 
  57 struct rt_sigframe {
  58         long dummy_er0;
  59         long dummy_vector;
  60 #if defined(CONFIG_CPU_H8S)
  61         short dummy_exr;
  62 #endif
  63         long dummy_pc;
  64         char *pretcode;
  65         struct siginfo *pinfo;
  66         void *puc;
  67         unsigned char retcode[8];
  68         struct siginfo info;
  69         struct ucontext uc;
  70         int sig;
  71 } __packed __aligned(2);
  72 
  73 static inline int
  74 restore_sigcontext(struct sigcontext *usc, int *pd0)
  75 {
  76         struct pt_regs *regs = current_pt_regs();
  77         int err = 0;
  78         unsigned int ccr;
  79         unsigned int usp;
  80         unsigned int er0;
  81 
  82         /* Always make any pending restarted system calls return -EINTR */
  83         current->restart_block.fn = do_no_restart_syscall;
  84 
  85         /* restore passed registers */
  86 #define COPY(r)  do { err |= get_user(regs->r, &usc->sc_##r); } while (0)
  87         COPY(er1);
  88         COPY(er2);
  89         COPY(er3);
  90         COPY(er5);
  91         COPY(pc);
  92         ccr = regs->ccr & 0x10;
  93         COPY(ccr);
  94 #undef COPY
  95         regs->ccr &= 0xef;
  96         regs->ccr |= ccr;
  97         regs->orig_er0 = -1;            /* disable syscall checks */
  98         err |= __get_user(usp, &usc->sc_usp);
  99         regs->sp = usp;
 100 
 101         err |= __get_user(er0, &usc->sc_er0);
 102         *pd0 = er0;
 103         return err;
 104 }
 105 
 106 asmlinkage int sys_rt_sigreturn(void)
 107 {
 108         unsigned long usp = rdusp();
 109         struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
 110         sigset_t set;
 111         int er0;
 112 
 113         if (!access_ok(frame, sizeof(*frame)))
 114                 goto badframe;
 115         if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 116                 goto badframe;
 117 
 118         set_current_blocked(&set);
 119 
 120         if (restore_sigcontext(&frame->uc.uc_mcontext, &er0))
 121                 goto badframe;
 122 
 123         if (restore_altstack(&frame->uc.uc_stack))
 124                 goto badframe;
 125 
 126         return er0;
 127 
 128 badframe:
 129         force_sig(SIGSEGV);
 130         return 0;
 131 }
 132 
 133 static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
 134                              unsigned long mask)
 135 {
 136         int err = 0;
 137 
 138         err |= __put_user(regs->er0, &sc->sc_er0);
 139         err |= __put_user(regs->er1, &sc->sc_er1);
 140         err |= __put_user(regs->er2, &sc->sc_er2);
 141         err |= __put_user(regs->er3, &sc->sc_er3);
 142         err |= __put_user(regs->er4, &sc->sc_er4);
 143         err |= __put_user(regs->er5, &sc->sc_er5);
 144         err |= __put_user(regs->er6, &sc->sc_er6);
 145         err |= __put_user(rdusp(),   &sc->sc_usp);
 146         err |= __put_user(regs->pc,  &sc->sc_pc);
 147         err |= __put_user(regs->ccr, &sc->sc_ccr);
 148         err |= __put_user(mask,      &sc->sc_mask);
 149 
 150         return err;
 151 }
 152 
 153 static inline void __user *
 154 get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size)
 155 {
 156         return (void __user *)((sigsp(rdusp(), ksig) - frame_size) & -8UL);
 157 }
 158 
 159 static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 160                           struct pt_regs *regs)
 161 {
 162         struct rt_sigframe *frame;
 163         int err = 0;
 164         unsigned char *ret;
 165 
 166         frame = get_sigframe(ksig, regs, sizeof(*frame));
 167 
 168         if (!access_ok(frame, sizeof(*frame)))
 169                 return -EFAULT;
 170 
 171         if (ksig->ka.sa.sa_flags & SA_SIGINFO)
 172                 err |= copy_siginfo_to_user(&frame->info, &ksig->info);
 173 
 174         /* Create the ucontext.  */
 175         err |= __put_user(0, &frame->uc.uc_flags);
 176         err |= __put_user(0, &frame->uc.uc_link);
 177         err |= __save_altstack(&frame->uc.uc_stack, rdusp());
 178         err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
 179         err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 180         if (err)
 181                 return -EFAULT;
 182 
 183         /* Set up to return from userspace.  */
 184         ret = (unsigned char *)&frame->retcode;
 185         if (ksig->ka.sa.sa_flags & SA_RESTORER)
 186                 ret = (unsigned char *)(ksig->ka.sa.sa_restorer);
 187         else {
 188                 /* sub.l er0,er0; mov.b #__NR_rt_sigreturn,r0l; trapa #0 */
 189                 err |= __put_user(0x1a80f800 + (__NR_rt_sigreturn & 0xff),
 190                                   (unsigned long *)(frame->retcode + 0));
 191                 err |= __put_user(0x5700,
 192                                   (unsigned short *)(frame->retcode + 4));
 193         }
 194         err |= __put_user(ret, &frame->pretcode);
 195 
 196         if (err)
 197                 return -EFAULT;
 198 
 199         /* Set up registers for signal handler */
 200         regs->sp  = (unsigned long)frame;
 201         regs->pc  = (unsigned long)ksig->ka.sa.sa_handler;
 202         regs->er0 = ksig->sig;
 203         regs->er1 = (unsigned long)&(frame->info);
 204         regs->er2 = (unsigned long)&frame->uc;
 205         regs->er5 = current->mm->start_data;    /* GOT base */
 206 
 207         return 0;
 208 }
 209 
 210 static void
 211 handle_restart(struct pt_regs *regs, struct k_sigaction *ka)
 212 {
 213         switch (regs->er0) {
 214         case -ERESTARTNOHAND:
 215                 if (!ka)
 216                         goto do_restart;
 217                 regs->er0 = -EINTR;
 218                 break;
 219         case -ERESTART_RESTARTBLOCK:
 220                 if (!ka) {
 221                         regs->er0 = __NR_restart_syscall;
 222                         regs->pc -= 2;
 223                 } else
 224                         regs->er0 = -EINTR;
 225                 break;
 226         case -ERESTARTSYS:
 227                 if (!(ka->sa.sa_flags & SA_RESTART)) {
 228                         regs->er0 = -EINTR;
 229                         break;
 230                 }
 231                 /* fallthrough */
 232         case -ERESTARTNOINTR:
 233 do_restart:
 234                 regs->er0 = regs->orig_er0;
 235                 regs->pc -= 2;
 236                 break;
 237         }
 238 }
 239 
 240 /*
 241  * OK, we're invoking a handler
 242  */
 243 static void
 244 handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 245 {
 246         sigset_t *oldset = sigmask_to_save();
 247         int ret;
 248         /* are we from a system call? */
 249         if (regs->orig_er0 >= 0)
 250                 handle_restart(regs, &ksig->ka);
 251 
 252         ret = setup_rt_frame(ksig, oldset, regs);
 253 
 254         signal_setup_done(ret, ksig, 0);
 255 }
 256 
 257 /*
 258  * Note that 'init' is a special process: it doesn't get signals it doesn't
 259  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 260  * mistake.
 261  */
 262 static void do_signal(struct pt_regs *regs)
 263 {
 264         struct ksignal ksig;
 265 
 266         current->thread.esp0 = (unsigned long) regs;
 267 
 268         if (get_signal(&ksig)) {
 269                 /* Whee!  Actually deliver the signal.  */
 270                 handle_signal(&ksig, regs);
 271                 return;
 272         }
 273         /* Did we come from a system call? */
 274         if (regs->orig_er0 >= 0)
 275                 handle_restart(regs, NULL);
 276 
 277         /* If there's no signal to deliver, we just restore the saved mask.  */
 278         restore_saved_sigmask();
 279 }
 280 
 281 asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
 282 {
 283         if (thread_info_flags & _TIF_SIGPENDING)
 284                 do_signal(regs);
 285 
 286         if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 287                 clear_thread_flag(TIF_NOTIFY_RESUME);
 288                 tracehook_notify_resume(regs);
 289         }
 290 }

/* [<][>][^][v][top][bottom][index][help] */