···11+/*22+ * OpenRISC Linux33+ *44+ * Linux architectural port borrowing liberally from similar works of55+ * others. All original copyrights apply as per the original source66+ * declaration.77+ *88+ * OpenRISC implementation:99+ * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>1010+ * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>1111+ * et al.1212+ *1313+ * This program is free software; you can redistribute it and/or modify1414+ * it under the terms of the GNU General Public License as published by1515+ * the Free Software Foundation; either version 2 of the License, or1616+ * (at your option) any later version.1717+ */1818+1919+#ifndef __ASM_OPENRISC_SIGCONTEXT_H2020+#define __ASM_OPENRISC_SIGCONTEXT_H2121+2222+#include <asm/ptrace.h>2323+2424+/* This struct is saved by setup_frame in signal.c, to keep the current2525+ context while a signal handler is executed. It's restored by sys_sigreturn.2626+2727+ To keep things simple, we use pt_regs here even though normally you just2828+ specify the list of regs to save. Then we can use copy_from_user on the2929+ entire regs instead of a bunch of get_user's as well...3030+*/3131+3232+struct sigcontext {3333+ struct pt_regs regs; /* needs to be first */3434+ unsigned long oldmask;3535+ unsigned long usp; /* usp before stacking this gunk on it */3636+};3737+3838+#endif /* __ASM_OPENRISC_SIGCONTEXT_H */
+396
arch/openrisc/kernel/signal.c
···11+/*22+ * OpenRISC signal.c33+ *44+ * Linux architectural port borrowing liberally from similar works of55+ * others. All original copyrights apply as per the original source66+ * declaration.77+ *88+ * Modifications for the OpenRISC architecture:99+ * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>1010+ * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>1111+ *1212+ * This program is free software; you can redistribute it and/or1313+ * modify it under the terms of the GNU General Public License1414+ * as published by the Free Software Foundation; either version1515+ * 2 of the License, or (at your option) any later version.1616+ */1717+1818+#include <linux/sched.h>1919+#include <linux/mm.h>2020+#include <linux/smp.h>2121+#include <linux/kernel.h>2222+#include <linux/signal.h>2323+#include <linux/errno.h>2424+#include <linux/wait.h>2525+#include <linux/ptrace.h>2626+#include <linux/unistd.h>2727+#include <linux/stddef.h>2828+#include <linux/tracehook.h>2929+3030+#include <asm/processor.h>3131+#include <asm/ucontext.h>3232+#include <asm/uaccess.h>3333+3434+#define DEBUG_SIG 03535+3636+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))3737+3838+asmlinkage long3939+_sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)4040+{4141+ return do_sigaltstack(uss, uoss, regs->sp);4242+}4343+4444+struct rt_sigframe {4545+ struct siginfo *pinfo;4646+ void *puc;4747+ struct siginfo info;4848+ struct ucontext uc;4949+ unsigned char retcode[16]; /* trampoline code */5050+};5151+5252+static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)5353+{5454+ unsigned int err = 0;5555+ unsigned long old_usp;5656+5757+ /* Alwys make any pending restarted system call return -EINTR */5858+ current_thread_info()->restart_block.fn = do_no_restart_syscall;5959+6060+ /* restore the regs from &sc->regs (same as sc, since regs is first)6161+ * (sc is already checked for VERIFY_READ since the sigframe was6262+ * checked in sys_sigreturn previously)6363+ */6464+6565+ if (__copy_from_user(regs, sc, sizeof(struct pt_regs)))6666+ goto badframe;6767+6868+ /* make sure the SM-bit is cleared so user-mode cannot fool us */6969+ regs->sr &= ~SPR_SR_SM;7070+7171+ /* restore the old USP as it was before we stacked the sc etc.7272+ * (we cannot just pop the sigcontext since we aligned the sp and7373+ * stuff after pushing it)7474+ */7575+7676+ err |= __get_user(old_usp, &sc->usp);7777+7878+ regs->sp = old_usp;7979+8080+ /* TODO: the other ports use regs->orig_XX to disable syscall checks8181+ * after this completes, but we don't use that mechanism. maybe we can8282+ * use it now ?8383+ */8484+8585+ return err;8686+8787+badframe:8888+ return 1;8989+}9090+9191+asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs)9292+{9393+ struct rt_sigframe *frame = (struct rt_sigframe __user *)regs->sp;9494+ sigset_t set;9595+ stack_t st;9696+9797+ /*9898+ * Since we stacked the signal on a dword boundary,9999+ * then frame should be dword aligned here. If it's100100+ * not, then the user is trying to mess with us.101101+ */102102+ if (((long)frame) & 3)103103+ goto badframe;104104+105105+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))106106+ goto badframe;107107+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))108108+ goto badframe;109109+110110+ sigdelsetmask(&set, ~_BLOCKABLE);111111+ spin_lock_irq(¤t->sighand->siglock);112112+ current->blocked = set;113113+ recalc_sigpending();114114+ spin_unlock_irq(¤t->sighand->siglock);115115+116116+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext))117117+ goto badframe;118118+119119+ if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))120120+ goto badframe;121121+ /* It is more difficult to avoid calling this function than to122122+ call it and ignore errors. */123123+ do_sigaltstack(&st, NULL, regs->sp);124124+125125+ return regs->gpr[11];126126+127127+badframe:128128+ force_sig(SIGSEGV, current);129129+ return 0;130130+}131131+132132+/*133133+ * Set up a signal frame.134134+ */135135+136136+static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,137137+ unsigned long mask)138138+{139139+ int err = 0;140140+ unsigned long usp = regs->sp;141141+142142+ /* copy the regs. they are first in sc so we can use sc directly */143143+144144+ err |= __copy_to_user(sc, regs, sizeof(struct pt_regs));145145+146146+ /* then some other stuff */147147+148148+ err |= __put_user(mask, &sc->oldmask);149149+150150+ err |= __put_user(usp, &sc->usp);151151+152152+ return err;153153+}154154+155155+static inline unsigned long align_sigframe(unsigned long sp)156156+{157157+ return sp & ~3UL;158158+}159159+160160+/*161161+ * Work out where the signal frame should go. It's either on the user stack162162+ * or the alternate stack.163163+ */164164+165165+static inline void __user *get_sigframe(struct k_sigaction *ka,166166+ struct pt_regs *regs, size_t frame_size)167167+{168168+ unsigned long sp = regs->sp;169169+ int onsigstack = on_sig_stack(sp);170170+171171+ /* redzone */172172+ sp -= STACK_FRAME_OVERHEAD;173173+174174+ /* This is the X/Open sanctioned signal stack switching. */175175+ if ((ka->sa.sa_flags & SA_ONSTACK) && !onsigstack) {176176+ if (current->sas_ss_size)177177+ sp = current->sas_ss_sp + current->sas_ss_size;178178+ }179179+180180+ sp = align_sigframe(sp - frame_size);181181+182182+ /*183183+ * If we are on the alternate signal stack and would overflow it, don't.184184+ * Return an always-bogus address instead so we will die with SIGSEGV.185185+ */186186+ if (onsigstack && !likely(on_sig_stack(sp)))187187+ return (void __user *)-1L;188188+189189+ return (void __user *)sp;190190+}191191+192192+/* grab and setup a signal frame.193193+ *194194+ * basically we stack a lot of state info, and arrange for the195195+ * user-mode program to return to the kernel using either a196196+ * trampoline which performs the syscall sigreturn, or a provided197197+ * user-mode trampoline.198198+ */199199+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,200200+ sigset_t *set, struct pt_regs *regs)201201+{202202+ struct rt_sigframe *frame;203203+ unsigned long return_ip;204204+ int err = 0;205205+206206+ frame = get_sigframe(ka, regs, sizeof(*frame));207207+208208+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))209209+ goto give_sigsegv;210210+211211+ err |= __put_user(&frame->info, &frame->pinfo);212212+ err |= __put_user(&frame->uc, &frame->puc);213213+214214+ if (ka->sa.sa_flags & SA_SIGINFO)215215+ err |= copy_siginfo_to_user(&frame->info, info);216216+ if (err)217217+ goto give_sigsegv;218218+219219+ /* Clear all the bits of the ucontext we don't use. */220220+ err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));221221+ err |= __put_user(0, &frame->uc.uc_flags);222222+ err |= __put_user(NULL, &frame->uc.uc_link);223223+ err |= __put_user((void *)current->sas_ss_sp,224224+ &frame->uc.uc_stack.ss_sp);225225+ err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags);226226+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);227227+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);228228+229229+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));230230+231231+ if (err)232232+ goto give_sigsegv;233233+234234+ /* trampoline - the desired return ip is the retcode itself */235235+ return_ip = (unsigned long)&frame->retcode;236236+ /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */237237+ err |= __put_user(0xa960, (short *)(frame->retcode + 0));238238+ err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2));239239+ err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));240240+ err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));241241+242242+ if (err)243243+ goto give_sigsegv;244244+245245+ /* TODO what is the current->exec_domain stuff and invmap ? */246246+247247+ /* Set up registers for signal handler */248248+ regs->pc = (unsigned long)ka->sa.sa_handler; /* what we enter NOW */249249+ regs->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */250250+ regs->gpr[3] = (unsigned long)sig; /* arg 1: signo */251251+ regs->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */252252+ regs->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */253253+254254+ /* actually move the usp to reflect the stacked frame */255255+ regs->sp = (unsigned long)frame;256256+257257+ return;258258+259259+give_sigsegv:260260+ if (sig == SIGSEGV)261261+ ka->sa.sa_handler = SIG_DFL;262262+ force_sig(SIGSEGV, current);263263+}264264+265265+static inline void266266+handle_signal(unsigned long sig,267267+ siginfo_t *info, struct k_sigaction *ka,268268+ sigset_t *oldset, struct pt_regs *regs)269269+{270270+ setup_rt_frame(sig, ka, info, oldset, regs);271271+272272+ if (ka->sa.sa_flags & SA_ONESHOT)273273+ ka->sa.sa_handler = SIG_DFL;274274+275275+ spin_lock_irq(¤t->sighand->siglock);276276+ sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);277277+ if (!(ka->sa.sa_flags & SA_NODEFER))278278+ sigaddset(¤t->blocked, sig);279279+ recalc_sigpending();280280+281281+ spin_unlock_irq(¤t->sighand->siglock);282282+}283283+284284+/*285285+ * Note that 'init' is a special process: it doesn't get signals it doesn't286286+ * want to handle. Thus you cannot kill init even with a SIGKILL even by287287+ * mistake.288288+ *289289+ * Also note that the regs structure given here as an argument, is the latest290290+ * pushed pt_regs. It may or may not be the same as the first pushed registers291291+ * when the initial usermode->kernelmode transition took place. Therefore292292+ * we can use user_mode(regs) to see if we came directly from kernel or user293293+ * mode below.294294+ */295295+296296+void do_signal(struct pt_regs *regs)297297+{298298+ siginfo_t info;299299+ int signr;300300+ struct k_sigaction ka;301301+302302+ /*303303+ * We want the common case to go fast, which304304+ * is why we may in certain cases get here from305305+ * kernel mode. Just return without doing anything306306+ * if so.307307+ */308308+ if (!user_mode(regs))309309+ return;310310+311311+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);312312+313313+ /* If we are coming out of a syscall then we need314314+ * to check if the syscall was interrupted and wants to be315315+ * restarted after handling the signal. If so, the original316316+ * syscall number is put back into r11 and the PC rewound to317317+ * point at the l.sys instruction that resulted in the318318+ * original syscall. Syscall results other than the four319319+ * below mean that the syscall executed to completion and no320320+ * restart is necessary.321321+ */322322+ if (regs->syscallno) {323323+ int restart = 0;324324+325325+ switch (regs->gpr[11]) {326326+ case -ERESTART_RESTARTBLOCK:327327+ case -ERESTARTNOHAND:328328+ /* Restart if there is no signal handler */329329+ restart = (signr <= 0);330330+ break;331331+ case -ERESTARTSYS:332332+ /* Restart if there no signal handler or333333+ * SA_RESTART flag is set */334334+ restart = (signr <= 0 || (ka.sa.sa_flags & SA_RESTART));335335+ break;336336+ case -ERESTARTNOINTR:337337+ /* Always restart */338338+ restart = 1;339339+ break;340340+ }341341+342342+ if (restart) {343343+ if (regs->gpr[11] == -ERESTART_RESTARTBLOCK)344344+ regs->gpr[11] = __NR_restart_syscall;345345+ else346346+ regs->gpr[11] = regs->orig_gpr11;347347+ regs->pc -= 4;348348+ } else {349349+ regs->gpr[11] = -EINTR;350350+ }351351+ }352352+353353+ if (signr <= 0) {354354+ /* no signal to deliver so we just put the saved sigmask355355+ * back */356356+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {357357+ clear_thread_flag(TIF_RESTORE_SIGMASK);358358+ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);359359+ }360360+361361+ } else { /* signr > 0 */362362+ sigset_t *oldset;363363+364364+ if (current_thread_info()->flags & _TIF_RESTORE_SIGMASK)365365+ oldset = ¤t->saved_sigmask;366366+ else367367+ oldset = ¤t->blocked;368368+369369+ /* Whee! Actually deliver the signal. */370370+ handle_signal(signr, &info, &ka, oldset, regs);371371+ /* a signal was successfully delivered; the saved372372+ * sigmask will have been stored in the signal frame,373373+ * and will be restored by sigreturn, so we can simply374374+ * clear the TIF_RESTORE_SIGMASK flag */375375+ if (test_thread_flag(TIF_RESTORE_SIGMASK))376376+ clear_thread_flag(TIF_RESTORE_SIGMASK);377377+378378+ tracehook_signal_handler(signr, &info, &ka, regs,379379+ test_thread_flag(TIF_SINGLESTEP));380380+ }381381+382382+ return;383383+}384384+385385+asmlinkage void do_notify_resume(struct pt_regs *regs)386386+{387387+ if (current_thread_info()->flags & _TIF_SIGPENDING)388388+ do_signal(regs);389389+390390+ if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) {391391+ clear_thread_flag(TIF_NOTIFY_RESUME);392392+ tracehook_notify_resume(regs);393393+ if (current->replacement_session_keyring)394394+ key_replace_session_keyring();395395+ }396396+}