The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arch/score/kernel/signal.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * arch/score/kernel/signal.c
    3  *
    4  * Score Processor version.
    5  *
    6  * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
    7  *  Chen Liqin <liqin.chen@sunplusct.com>
    8  *  Lennox Wu <lennox.wu@sunplusct.com>
    9  *
   10  * This program is free software; you can redistribute it and/or modify
   11  * it under the terms of the GNU General Public License as published by
   12  * the Free Software Foundation; either version 2 of the License, or
   13  * (at your option) any later version.
   14  *
   15  * This program is distributed in the hope that it will be useful,
   16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18  * GNU General Public License for more details.
   19  *
   20  * You should have received a copy of the GNU General Public License
   21  * along with this program; if not, see the file COPYING, or write
   22  * to the Free Software Foundation, Inc.,
   23  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   24  */
   25 
   26 #include <linux/errno.h>
   27 #include <linux/signal.h>
   28 #include <linux/ptrace.h>
   29 #include <linux/unistd.h>
   30 #include <linux/uaccess.h>
   31 #include <linux/tracehook.h>
   32 
   33 #include <asm/cacheflush.h>
   34 #include <asm/syscalls.h>
   35 #include <asm/ucontext.h>
   36 
   37 struct rt_sigframe {
   38         u32 rs_ass[4];          /* argument save space */
   39         u32 rs_code[2];         /* signal trampoline */
   40         struct siginfo rs_info;
   41         struct ucontext rs_uc;
   42 };
   43 
   44 static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
   45 {
   46         int err = 0;
   47         unsigned long reg;
   48 
   49         reg = regs->cp0_epc; err |= __put_user(reg, &sc->sc_pc);
   50         err |= __put_user(regs->cp0_psr, &sc->sc_psr);
   51         err |= __put_user(regs->cp0_condition, &sc->sc_condition);
   52 
   53 
   54 #define save_gp_reg(i) {                                \
   55         reg = regs->regs[i];                            \
   56         err |= __put_user(reg, &sc->sc_regs[i]);        \
   57 } while (0)
   58         save_gp_reg(0); save_gp_reg(1); save_gp_reg(2);
   59         save_gp_reg(3); save_gp_reg(4); save_gp_reg(5);
   60         save_gp_reg(6); save_gp_reg(7); save_gp_reg(8);
   61         save_gp_reg(9); save_gp_reg(10); save_gp_reg(11);
   62         save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
   63         save_gp_reg(15); save_gp_reg(16); save_gp_reg(17);
   64         save_gp_reg(18); save_gp_reg(19); save_gp_reg(20);
   65         save_gp_reg(21); save_gp_reg(22); save_gp_reg(23);
   66         save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
   67         save_gp_reg(27); save_gp_reg(28); save_gp_reg(29);
   68 #undef save_gp_reg
   69 
   70         reg = regs->ceh; err |= __put_user(reg, &sc->sc_mdceh);
   71         reg = regs->cel; err |= __put_user(reg, &sc->sc_mdcel);
   72         err |= __put_user(regs->cp0_ecr, &sc->sc_ecr);
   73         err |= __put_user(regs->cp0_ema, &sc->sc_ema);
   74 
   75         return err;
   76 }
   77 
   78 static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
   79 {
   80         int err = 0;
   81         u32 reg;
   82 
   83         err |= __get_user(regs->cp0_epc, &sc->sc_pc);
   84         err |= __get_user(regs->cp0_condition, &sc->sc_condition);
   85 
   86         err |= __get_user(reg, &sc->sc_mdceh);
   87         regs->ceh = (int) reg;
   88         err |= __get_user(reg, &sc->sc_mdcel);
   89         regs->cel = (int) reg;
   90 
   91         err |= __get_user(reg, &sc->sc_psr);
   92         regs->cp0_psr = (int) reg;
   93         err |= __get_user(reg, &sc->sc_ecr);
   94         regs->cp0_ecr = (int) reg;
   95         err |= __get_user(reg, &sc->sc_ema);
   96         regs->cp0_ema = (int) reg;
   97 
   98 #define restore_gp_reg(i) do {                          \
   99         err |= __get_user(reg, &sc->sc_regs[i]);        \
  100         regs->regs[i] = reg;                            \
  101 } while (0)
  102         restore_gp_reg(0); restore_gp_reg(1); restore_gp_reg(2);
  103         restore_gp_reg(3); restore_gp_reg(4); restore_gp_reg(5);
  104         restore_gp_reg(6); restore_gp_reg(7); restore_gp_reg(8);
  105         restore_gp_reg(9); restore_gp_reg(10); restore_gp_reg(11);
  106         restore_gp_reg(12); restore_gp_reg(13); restore_gp_reg(14);
  107         restore_gp_reg(15); restore_gp_reg(16); restore_gp_reg(17);
  108         restore_gp_reg(18); restore_gp_reg(19); restore_gp_reg(20);
  109         restore_gp_reg(21); restore_gp_reg(22); restore_gp_reg(23);
  110         restore_gp_reg(24); restore_gp_reg(25); restore_gp_reg(26);
  111         restore_gp_reg(27); restore_gp_reg(28); restore_gp_reg(29);
  112 #undef restore_gp_reg
  113 
  114         return err;
  115 }
  116 
  117 /*
  118  * Determine which stack to use..
  119  */
  120 static void __user *get_sigframe(struct k_sigaction *ka,
  121                         struct pt_regs *regs, size_t frame_size)
  122 {
  123         unsigned long sp;
  124 
  125         /* Default to using normal stack */
  126         sp = regs->regs[0];
  127         sp -= 32;
  128 
  129         /* This is the X/Open sanctioned signal stack switching.  */
  130         if ((ka->sa.sa_flags & SA_ONSTACK) && (!on_sig_stack(sp)))
  131                 sp = current->sas_ss_sp + current->sas_ss_size;
  132 
  133         return (void __user*)((sp - frame_size) & ~7);
  134 }
  135 
  136 asmlinkage long
  137 score_sigaltstack(struct pt_regs *regs)
  138 {
  139         const stack_t __user *uss = (const stack_t __user *) regs->regs[4];
  140         stack_t __user *uoss = (stack_t __user *) regs->regs[5];
  141         unsigned long usp = regs->regs[0];
  142 
  143         return do_sigaltstack(uss, uoss, usp);
  144 }
  145 
  146 asmlinkage long
  147 score_rt_sigreturn(struct pt_regs *regs)
  148 {
  149         struct rt_sigframe __user *frame;
  150         sigset_t set;
  151         int sig;
  152 
  153         /* Always make any pending restarted system calls return -EINTR */
  154         current_thread_info()->restart_block.fn = do_no_restart_syscall;
  155 
  156         frame = (struct rt_sigframe __user *) regs->regs[0];
  157         if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
  158                 goto badframe;
  159         if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
  160                 goto badframe;
  161 
  162         set_current_blocked(&set);
  163 
  164         sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext);
  165         if (sig < 0)
  166                 goto badframe;
  167         else if (sig)
  168                 force_sig(sig, current);
  169 
  170         /* It is more difficult to avoid calling this function than to
  171            call it and ignore errors.  */
  172         if (do_sigaltstack(&frame->rs_uc.uc_stack, NULL, regs->regs[0]) == -EFAULT)
  173                 goto badframe;
  174         regs->is_syscall = 0;
  175 
  176         __asm__ __volatile__(
  177                 "mv\tr0, %0\n\t"
  178                 "la\tr8, syscall_exit\n\t"
  179                 "br\tr8\n\t"
  180                 : : "r" (regs) : "r8");
  181 
  182 badframe:
  183         force_sig(SIGSEGV, current);
  184 
  185         return 0;
  186 }
  187 
  188 static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
  189                 int signr, sigset_t *set, siginfo_t *info)
  190 {
  191         struct rt_sigframe __user *frame;
  192         int err = 0;
  193 
  194         frame = get_sigframe(ka, regs, sizeof(*frame));
  195         if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
  196                 goto give_sigsegv;
  197 
  198         /*
  199          * Set up the return code ...
  200          *
  201          *         li      v0, __NR_rt_sigreturn
  202          *         syscall
  203          */
  204         err |= __put_user(0x87788000 + __NR_rt_sigreturn*2,
  205                         frame->rs_code + 0);
  206         err |= __put_user(0x80008002, frame->rs_code + 1);
  207         flush_cache_sigtramp((unsigned long) frame->rs_code);
  208 
  209         err |= copy_siginfo_to_user(&frame->rs_info, info);
  210         err |= __put_user(0, &frame->rs_uc.uc_flags);
  211         err |= __put_user(NULL, &frame->rs_uc.uc_link);
  212         err |= __put_user((void __user *)current->sas_ss_sp,
  213                                 &frame->rs_uc.uc_stack.ss_sp);
  214         err |= __put_user(sas_ss_flags(regs->regs[0]),
  215                                 &frame->rs_uc.uc_stack.ss_flags);
  216         err |= __put_user(current->sas_ss_size,
  217                                 &frame->rs_uc.uc_stack.ss_size);
  218         err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
  219         err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
  220 
  221         if (err)
  222                 goto give_sigsegv;
  223 
  224         regs->regs[0] = (unsigned long) frame;
  225         regs->regs[3] = (unsigned long) frame->rs_code;
  226         regs->regs[4] = signr;
  227         regs->regs[5] = (unsigned long) &frame->rs_info;
  228         regs->regs[6] = (unsigned long) &frame->rs_uc;
  229         regs->regs[29] = (unsigned long) ka->sa.sa_handler;
  230         regs->cp0_epc = (unsigned long) ka->sa.sa_handler;
  231 
  232         return 0;
  233 
  234 give_sigsegv:
  235         force_sigsegv(signr, current);
  236         return -EFAULT;
  237 }
  238 
  239 static void handle_signal(unsigned long sig, siginfo_t *info,
  240         struct k_sigaction *ka, struct pt_regs *regs)
  241 {
  242         if (regs->is_syscall) {
  243                 switch (regs->regs[4]) {
  244                 case ERESTART_RESTARTBLOCK:
  245                 case ERESTARTNOHAND:
  246                         regs->regs[4] = EINTR;
  247                         break;
  248                 case ERESTARTSYS:
  249                         if (!(ka->sa.sa_flags & SA_RESTART)) {
  250                                 regs->regs[4] = EINTR;
  251                                 break;
  252                         }
  253                 case ERESTARTNOINTR:
  254                         regs->regs[4] = regs->orig_r4;
  255                         regs->regs[7] = regs->orig_r7;
  256                         regs->cp0_epc -= 8;
  257                 }
  258 
  259                 regs->is_syscall = 0;
  260         }
  261 
  262         /*
  263          * Set up the stack frame
  264          */
  265         if (setup_rt_frame(ka, regs, sig, sigmask_to_save(), info) < 0)
  266                 return;
  267 
  268         signal_delivered(sig, info, ka, regs, 0);
  269 }
  270 
  271 static void do_signal(struct pt_regs *regs)
  272 {
  273         struct k_sigaction ka;
  274         siginfo_t info;
  275         int signr;
  276 
  277         /*
  278          * We want the common case to go fast, which is why we may in certain
  279          * cases get here from kernel mode. Just return without doing anything
  280          * if so.
  281          */
  282         if (!user_mode(regs))
  283                 return;
  284 
  285         signr = get_signal_to_deliver(&info, &ka, regs, NULL);
  286         if (signr > 0) {
  287                 /* Actually deliver the signal.  */
  288                 handle_signal(signr, &info, &ka, regs);
  289                 return;
  290         }
  291 
  292         if (regs->is_syscall) {
  293                 if (regs->regs[4] == ERESTARTNOHAND ||
  294                     regs->regs[4] == ERESTARTSYS ||
  295                     regs->regs[4] == ERESTARTNOINTR) {
  296                         regs->regs[4] = regs->orig_r4;
  297                         regs->regs[7] = regs->orig_r7;
  298                         regs->cp0_epc -= 8;
  299                 }
  300 
  301                 if (regs->regs[4] == ERESTART_RESTARTBLOCK) {
  302                         regs->regs[27] = __NR_restart_syscall;
  303                         regs->regs[4] = regs->orig_r4;
  304                         regs->regs[7] = regs->orig_r7;
  305                         regs->cp0_epc -= 8;
  306                 }
  307 
  308                 regs->is_syscall = 0;   /* Don't deal with this again.  */
  309         }
  310 
  311         /*
  312          * If there's no signal to deliver, we just put the saved sigmask
  313          * back
  314          */
  315         restore_saved_sigmask();
  316 }
  317 
  318 /*
  319  * notification of userspace execution resumption
  320  * - triggered by the TIF_WORK_MASK flags
  321  */
  322 asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
  323                                 __u32 thread_info_flags)
  324 {
  325         /* deal with pending signal delivery */
  326         if (thread_info_flags & _TIF_SIGPENDING)
  327                 do_signal(regs);
  328         if (thread_info_flags & _TIF_NOTIFY_RESUME) {
  329                 clear_thread_flag(TIF_NOTIFY_RESUME);
  330                 tracehook_notify_resume(regs);
  331         }
  332 }

Cache object: 6128baadf5986c91d786ecc1e81a0eba


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.