5a0e3ad6af
percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
677 lines
17 KiB
C
677 lines
17 KiB
C
/*
|
|
* Copyright (C) 2003, Axis Communications AB.
|
|
*/
|
|
|
|
#include <linux/sched.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/signal.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/unistd.h>
|
|
#include <linux/stddef.h>
|
|
#include <linux/syscalls.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/ucontext.h>
|
|
#include <asm/uaccess.h>
|
|
#include <arch/ptrace.h>
|
|
#include <arch/hwregs/cpu_vect.h>
|
|
|
|
extern unsigned long cris_signal_return_page;
|
|
|
|
/* Flag to check if a signal is blockable. */
|
|
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
|
|
|
/*
|
|
* A syscall in CRIS is really a "break 13" instruction, which is 2
|
|
* bytes. The registers is manipulated so upon return the instruction
|
|
* will be executed again.
|
|
*
|
|
* This relies on that PC points to the instruction after the break call.
|
|
*/
|
|
#define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->erp -= 2;
|
|
|
|
/* Signal frames. */
|
|
struct signal_frame {
|
|
struct sigcontext sc;
|
|
unsigned long extramask[_NSIG_WORDS - 1];
|
|
unsigned char retcode[8]; /* Trampoline code. */
|
|
};
|
|
|
|
struct rt_signal_frame {
|
|
struct siginfo *pinfo;
|
|
void *puc;
|
|
struct siginfo info;
|
|
struct ucontext uc;
|
|
unsigned char retcode[8]; /* Trampoline code. */
|
|
};
|
|
|
|
void do_signal(int restart, struct pt_regs *regs);
|
|
void keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
|
|
struct pt_regs *regs);
|
|
/*
|
|
* Swap in the new signal mask, and wait for a signal. Define some
|
|
* dummy arguments to be able to reach the regs argument.
|
|
*/
|
|
int
|
|
sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
|
|
long srp, struct pt_regs *regs)
|
|
{
|
|
mask &= _BLOCKABLE;
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
current->saved_sigmask = current->blocked;
|
|
siginitset(¤t->blocked, mask);
|
|
recalc_sigpending();
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
current->state = TASK_INTERRUPTIBLE;
|
|
schedule();
|
|
set_thread_flag(TIF_RESTORE_SIGMASK);
|
|
return -ERESTARTNOHAND;
|
|
}
|
|
|
|
int
|
|
sys_sigaction(int signal, const struct old_sigaction *act,
|
|
struct old_sigaction *oact)
|
|
{
|
|
int retval;
|
|
struct k_sigaction newk;
|
|
struct k_sigaction oldk;
|
|
|
|
if (act) {
|
|
old_sigset_t mask;
|
|
|
|
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
|
|
__get_user(newk.sa.sa_handler, &act->sa_handler) ||
|
|
__get_user(newk.sa.sa_restorer, &act->sa_restorer))
|
|
return -EFAULT;
|
|
|
|
__get_user(newk.sa.sa_flags, &act->sa_flags);
|
|
__get_user(mask, &act->sa_mask);
|
|
siginitset(&newk.sa.sa_mask, mask);
|
|
}
|
|
|
|
retval = do_sigaction(signal, act ? &newk : NULL, oact ? &oldk : NULL);
|
|
|
|
if (!retval && oact) {
|
|
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
|
|
__put_user(oldk.sa.sa_handler, &oact->sa_handler) ||
|
|
__put_user(oldk.sa.sa_restorer, &oact->sa_restorer))
|
|
return -EFAULT;
|
|
|
|
__put_user(oldk.sa.sa_flags, &oact->sa_flags);
|
|
__put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
int
|
|
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
|
|
{
|
|
return do_sigaltstack(uss, uoss, rdusp());
|
|
}
|
|
|
|
static int
|
|
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
|
|
{
|
|
unsigned int err = 0;
|
|
unsigned long old_usp;
|
|
|
|
/* Always make any pending restarted system calls return -EINTR */
|
|
current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
|
|
|
/*
|
|
* Restore the registers from &sc->regs. sc is already checked
|
|
* for VERIFY_READ since the signal_frame was previously
|
|
* checked in sys_sigreturn().
|
|
*/
|
|
if (__copy_from_user(regs, sc, sizeof(struct pt_regs)))
|
|
goto badframe;
|
|
|
|
/* Make that the user-mode flag is set. */
|
|
regs->ccs |= (1 << (U_CCS_BITNR + CCS_SHIFT));
|
|
|
|
/* Restore the old USP. */
|
|
err |= __get_user(old_usp, &sc->usp);
|
|
wrusp(old_usp);
|
|
|
|
return err;
|
|
|
|
badframe:
|
|
return 1;
|
|
}
|
|
|
|
/* Define some dummy arguments to be able to reach the regs argument. */
|
|
asmlinkage int
|
|
sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
|
|
struct pt_regs *regs)
|
|
{
|
|
sigset_t set;
|
|
struct signal_frame __user *frame;
|
|
unsigned long oldspc = regs->spc;
|
|
unsigned long oldccs = regs->ccs;
|
|
|
|
frame = (struct signal_frame *) rdusp();
|
|
|
|
/*
|
|
* Since the signal is stacked on a dword boundary, the frame
|
|
* should be dword aligned here as well. It it's not, then the
|
|
* user is trying some funny business.
|
|
*/
|
|
if (((long)frame) & 3)
|
|
goto badframe;
|
|
|
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
|
goto badframe;
|
|
|
|
if (__get_user(set.sig[0], &frame->sc.oldmask) ||
|
|
(_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1],
|
|
frame->extramask,
|
|
sizeof(frame->extramask))))
|
|
goto badframe;
|
|
|
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
|
|
current->blocked = set;
|
|
|
|
recalc_sigpending();
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
|
|
if (restore_sigcontext(regs, &frame->sc))
|
|
goto badframe;
|
|
|
|
keep_debug_flags(oldccs, oldspc, regs);
|
|
|
|
return regs->r10;
|
|
|
|
badframe:
|
|
force_sig(SIGSEGV, current);
|
|
return 0;
|
|
}
|
|
|
|
/* Define some dummy variables to be able to reach the regs argument. */
|
|
asmlinkage int
|
|
sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
|
|
struct pt_regs *regs)
|
|
{
|
|
sigset_t set;
|
|
struct rt_signal_frame __user *frame;
|
|
unsigned long oldspc = regs->spc;
|
|
unsigned long oldccs = regs->ccs;
|
|
|
|
frame = (struct rt_signal_frame *) rdusp();
|
|
|
|
/*
|
|
* Since the signal is stacked on a dword boundary, the frame
|
|
* should be dword aligned here as well. It it's not, then the
|
|
* user is trying some funny business.
|
|
*/
|
|
if (((long)frame) & 3)
|
|
goto badframe;
|
|
|
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
|
goto badframe;
|
|
|
|
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
|
goto badframe;
|
|
|
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
|
|
current->blocked = set;
|
|
|
|
recalc_sigpending();
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
|
|
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
|
|
goto badframe;
|
|
|
|
if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
|
|
goto badframe;
|
|
|
|
keep_debug_flags(oldccs, oldspc, regs);
|
|
|
|
return regs->r10;
|
|
|
|
badframe:
|
|
force_sig(SIGSEGV, current);
|
|
return 0;
|
|
}
|
|
|
|
/* Setup a signal frame. */
|
|
static int
|
|
setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
|
|
unsigned long mask)
|
|
{
|
|
int err;
|
|
unsigned long usp;
|
|
|
|
err = 0;
|
|
usp = rdusp();
|
|
|
|
/*
|
|
* Copy the registers. They are located first in sc, so it's
|
|
* possible to use sc directly.
|
|
*/
|
|
err |= __copy_to_user(sc, regs, sizeof(struct pt_regs));
|
|
|
|
err |= __put_user(mask, &sc->oldmask);
|
|
err |= __put_user(usp, &sc->usp);
|
|
|
|
return err;
|
|
}
|
|
|
|
/* Figure out where to put the new signal frame - usually on the stack. */
|
|
static inline void __user *
|
|
get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
|
|
{
|
|
unsigned long sp;
|
|
|
|
sp = rdusp();
|
|
|
|
/* This is the X/Open sanctioned signal stack switching. */
|
|
if (ka->sa.sa_flags & SA_ONSTACK) {
|
|
if (!on_sig_stack(sp))
|
|
sp = current->sas_ss_sp + current->sas_ss_size;
|
|
}
|
|
|
|
/* Make sure the frame is dword-aligned. */
|
|
sp &= ~3;
|
|
|
|
return (void __user *)(sp - frame_size);
|
|
}
|
|
|
|
/* Grab and setup a signal frame.
|
|
*
|
|
* Basically a lot of state-info is stacked, and arranged for the
|
|
* user-mode program to return to the kernel using either a trampiline
|
|
* which performs the syscall sigreturn(), or a provided user-mode
|
|
* trampoline.
|
|
*/
|
|
static int
|
|
setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
|
struct pt_regs * regs)
|
|
{
|
|
int err;
|
|
unsigned long return_ip;
|
|
struct signal_frame __user *frame;
|
|
|
|
err = 0;
|
|
frame = get_sigframe(ka, regs, sizeof(*frame));
|
|
|
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
|
goto give_sigsegv;
|
|
|
|
err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
|
|
|
|
if (err)
|
|
goto give_sigsegv;
|
|
|
|
if (_NSIG_WORDS > 1) {
|
|
err |= __copy_to_user(frame->extramask, &set->sig[1],
|
|
sizeof(frame->extramask));
|
|
}
|
|
|
|
if (err)
|
|
goto give_sigsegv;
|
|
|
|
/*
|
|
* Set up to return from user-space. If provided, use a stub
|
|
* already located in user-space.
|
|
*/
|
|
if (ka->sa.sa_flags & SA_RESTORER) {
|
|
return_ip = (unsigned long)ka->sa.sa_restorer;
|
|
} else {
|
|
/* Trampoline - the desired return ip is in the signal return page. */
|
|
return_ip = cris_signal_return_page;
|
|
|
|
/*
|
|
* This is movu.w __NR_sigreturn, r9; break 13;
|
|
*
|
|
* WE DO NOT USE IT ANY MORE! It's only left here for historical
|
|
* reasons and because gdb uses it as a signature to notice
|
|
* signal handler stack frames.
|
|
*/
|
|
err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
|
|
err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2));
|
|
err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
|
|
}
|
|
|
|
if (err)
|
|
goto give_sigsegv;
|
|
|
|
/*
|
|
* Set up registers for signal handler.
|
|
*
|
|
* Where the code enters now.
|
|
* Where the code enter later.
|
|
* First argument, signo.
|
|
*/
|
|
regs->erp = (unsigned long) ka->sa.sa_handler;
|
|
regs->srp = return_ip;
|
|
regs->r10 = sig;
|
|
|
|
/* Actually move the USP to reflect the stacked frame. */
|
|
wrusp((unsigned long)frame);
|
|
|
|
return 0;
|
|
|
|
give_sigsegv:
|
|
if (sig == SIGSEGV)
|
|
ka->sa.sa_handler = SIG_DFL;
|
|
|
|
force_sig(SIGSEGV, current);
|
|
return -EFAULT;
|
|
}
|
|
|
|
static int
|
|
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|
sigset_t *set, struct pt_regs * regs)
|
|
{
|
|
int err;
|
|
unsigned long return_ip;
|
|
struct rt_signal_frame __user *frame;
|
|
|
|
err = 0;
|
|
frame = get_sigframe(ka, regs, sizeof(*frame));
|
|
|
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
|
goto give_sigsegv;
|
|
|
|
/* TODO: what is the current->exec_domain stuff and invmap ? */
|
|
|
|
err |= __put_user(&frame->info, &frame->pinfo);
|
|
err |= __put_user(&frame->uc, &frame->puc);
|
|
err |= copy_siginfo_to_user(&frame->info, info);
|
|
|
|
if (err)
|
|
goto give_sigsegv;
|
|
|
|
/* Clear all the bits of the ucontext we don't use. */
|
|
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
|
|
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
|
|
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
|
|
|
if (err)
|
|
goto give_sigsegv;
|
|
|
|
/*
|
|
* Set up to return from user-space. If provided, use a stub
|
|
* already located in user-space.
|
|
*/
|
|
if (ka->sa.sa_flags & SA_RESTORER) {
|
|
return_ip = (unsigned long) ka->sa.sa_restorer;
|
|
} else {
|
|
/* Trampoline - the desired return ip is in the signal return page. */
|
|
return_ip = cris_signal_return_page + 6;
|
|
|
|
/*
|
|
* This is movu.w __NR_rt_sigreturn, r9; break 13;
|
|
*
|
|
* WE DO NOT USE IT ANY MORE! It's only left here for historical
|
|
* reasons and because gdb uses it as a signature to notice
|
|
* signal handler stack frames.
|
|
*/
|
|
err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
|
|
|
|
err |= __put_user(__NR_rt_sigreturn,
|
|
(short __user*)(frame->retcode+2));
|
|
|
|
err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
|
|
}
|
|
|
|
if (err)
|
|
goto give_sigsegv;
|
|
|
|
/*
|
|
* Set up registers for signal handler.
|
|
*
|
|
* Where the code enters now.
|
|
* Where the code enters later.
|
|
* First argument is signo.
|
|
* Second argument is (siginfo_t *).
|
|
* Third argument is unused.
|
|
*/
|
|
regs->erp = (unsigned long) ka->sa.sa_handler;
|
|
regs->srp = return_ip;
|
|
regs->r10 = sig;
|
|
regs->r11 = (unsigned long) &frame->info;
|
|
regs->r12 = 0;
|
|
|
|
/* Actually move the usp to reflect the stacked frame. */
|
|
wrusp((unsigned long)frame);
|
|
|
|
return 0;
|
|
|
|
give_sigsegv:
|
|
if (sig == SIGSEGV)
|
|
ka->sa.sa_handler = SIG_DFL;
|
|
|
|
force_sig(SIGSEGV, current);
|
|
return -EFAULT;
|
|
}
|
|
|
|
/* Invoke a signal handler to, well, handle the signal. */
|
|
static inline int
|
|
handle_signal(int canrestart, unsigned long sig,
|
|
siginfo_t *info, struct k_sigaction *ka,
|
|
sigset_t *oldset, struct pt_regs * regs)
|
|
{
|
|
int ret;
|
|
|
|
/* Check if this got called from a system call. */
|
|
if (canrestart) {
|
|
/* If so, check system call restarting. */
|
|
switch (regs->r10) {
|
|
case -ERESTART_RESTARTBLOCK:
|
|
case -ERESTARTNOHAND:
|
|
/*
|
|
* This means that the syscall should
|
|
* only be restarted if there was no
|
|
* handler for the signal, and since
|
|
* this point isn't reached unless
|
|
* there is a handler, there's no need
|
|
* to restart.
|
|
*/
|
|
regs->r10 = -EINTR;
|
|
break;
|
|
|
|
case -ERESTARTSYS:
|
|
/*
|
|
* This means restart the syscall if
|
|
* there is no handler, or the handler
|
|
* was registered with SA_RESTART.
|
|
*/
|
|
if (!(ka->sa.sa_flags & SA_RESTART)) {
|
|
regs->r10 = -EINTR;
|
|
break;
|
|
}
|
|
|
|
/* Fall through. */
|
|
|
|
case -ERESTARTNOINTR:
|
|
/*
|
|
* This means that the syscall should
|
|
* be called again after the signal
|
|
* handler returns.
|
|
*/
|
|
RESTART_CRIS_SYS(regs);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Set up the stack frame. */
|
|
if (ka->sa.sa_flags & SA_SIGINFO)
|
|
ret = setup_rt_frame(sig, ka, info, oldset, regs);
|
|
else
|
|
ret = setup_frame(sig, ka, oldset, regs);
|
|
|
|
if (ka->sa.sa_flags & SA_ONESHOT)
|
|
ka->sa.sa_handler = SIG_DFL;
|
|
|
|
if (ret == 0) {
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
sigorsets(¤t->blocked, ¤t->blocked,
|
|
&ka->sa.sa_mask);
|
|
if (!(ka->sa.sa_flags & SA_NODEFER))
|
|
sigaddset(¤t->blocked, sig);
|
|
recalc_sigpending();
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Note that 'init' is a special process: it doesn't get signals it doesn't
|
|
* want to handle. Thus you cannot kill init even with a SIGKILL even by
|
|
* mistake.
|
|
*
|
|
* Also note that the regs structure given here as an argument, is the latest
|
|
* pushed pt_regs. It may or may not be the same as the first pushed registers
|
|
* when the initial usermode->kernelmode transition took place. Therefore
|
|
* we can use user_mode(regs) to see if we came directly from kernel or user
|
|
* mode below.
|
|
*/
|
|
void
|
|
do_signal(int canrestart, struct pt_regs *regs)
|
|
{
|
|
int signr;
|
|
siginfo_t info;
|
|
struct k_sigaction ka;
|
|
sigset_t *oldset;
|
|
|
|
/*
|
|
* The common case should go fast, which is why this point is
|
|
* reached from kernel-mode. If that's the case, just return
|
|
* without doing anything.
|
|
*/
|
|
if (!user_mode(regs))
|
|
return;
|
|
|
|
if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
|
oldset = ¤t->saved_sigmask;
|
|
else
|
|
oldset = ¤t->blocked;
|
|
|
|
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
|
|
|
if (signr > 0) {
|
|
/* Whee! Actually deliver the signal. */
|
|
if (handle_signal(canrestart, signr, &info, &ka,
|
|
oldset, regs)) {
|
|
/* a signal was successfully delivered; the saved
|
|
* sigmask will have been stored in the signal frame,
|
|
* and will be restored by sigreturn, so we can simply
|
|
* clear the TIF_RESTORE_SIGMASK flag */
|
|
if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
|
clear_thread_flag(TIF_RESTORE_SIGMASK);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* Got here from a system call? */
|
|
if (canrestart) {
|
|
/* Restart the system call - no handlers present. */
|
|
if (regs->r10 == -ERESTARTNOHAND ||
|
|
regs->r10 == -ERESTARTSYS ||
|
|
regs->r10 == -ERESTARTNOINTR) {
|
|
RESTART_CRIS_SYS(regs);
|
|
}
|
|
|
|
if (regs->r10 == -ERESTART_RESTARTBLOCK){
|
|
regs->r10 = __NR_restart_syscall;
|
|
regs->erp -= 2;
|
|
}
|
|
}
|
|
|
|
/* if there's no signal to deliver, we just put the saved sigmask
|
|
* back */
|
|
if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
|
|
clear_thread_flag(TIF_RESTORE_SIGMASK);
|
|
sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
|
|
}
|
|
}
|
|
|
|
asmlinkage void
|
|
ugdb_trap_user(struct thread_info *ti, int sig)
|
|
{
|
|
if (((user_regs(ti)->exs & 0xff00) >> 8) != SINGLE_STEP_INTR_VECT) {
|
|
/* Zero single-step PC if the reason we stopped wasn't a single
|
|
step exception. This is to avoid relying on it when it isn't
|
|
reliable. */
|
|
user_regs(ti)->spc = 0;
|
|
}
|
|
/* FIXME: Filter out false h/w breakpoint hits (i.e. EDA
|
|
not withing any configured h/w breakpoint range). Synchronize with
|
|
what already exists for kernel debugging. */
|
|
if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) {
|
|
/* Break 8: subtract 2 from ERP unless in a delay slot. */
|
|
if (!(user_regs(ti)->erp & 0x1))
|
|
user_regs(ti)->erp -= 2;
|
|
}
|
|
sys_kill(ti->task->pid, sig);
|
|
}
|
|
|
|
void
|
|
keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
|
|
struct pt_regs *regs)
|
|
{
|
|
if (oldccs & (1 << Q_CCS_BITNR)) {
|
|
/* Pending single step due to single-stepping the break 13
|
|
in the signal trampoline: keep the Q flag. */
|
|
regs->ccs |= (1 << Q_CCS_BITNR);
|
|
/* S flag should be set - complain if it's not. */
|
|
if (!(oldccs & (1 << (S_CCS_BITNR + CCS_SHIFT)))) {
|
|
printk("Q flag but no S flag?");
|
|
}
|
|
regs->ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT));
|
|
/* Assume the SPC is valid and interesting. */
|
|
regs->spc = oldspc;
|
|
|
|
} else if (oldccs & (1 << (S_CCS_BITNR + CCS_SHIFT))) {
|
|
/* If a h/w bp was set in the signal handler we need
|
|
to keep the S flag. */
|
|
regs->ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT));
|
|
/* Don't keep the old SPC though; if we got here due to
|
|
a single-step, the Q flag should have been set. */
|
|
} else if (regs->spc) {
|
|
/* If we were single-stepping *before* the signal was taken,
|
|
we don't want to restore that state now, because GDB will
|
|
have forgotten all about it. */
|
|
regs->spc = 0;
|
|
regs->ccs &= ~(1 << (S_CCS_BITNR + CCS_SHIFT));
|
|
}
|
|
}
|
|
|
|
/* Set up the trampolines on the signal return page. */
|
|
int __init
|
|
cris_init_signal(void)
|
|
{
|
|
u16* data = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
|
|
|
/* This is movu.w __NR_sigreturn, r9; break 13; */
|
|
data[0] = 0x9c5f;
|
|
data[1] = __NR_sigreturn;
|
|
data[2] = 0xe93d;
|
|
/* This is movu.w __NR_rt_sigreturn, r9; break 13; */
|
|
data[3] = 0x9c5f;
|
|
data[4] = __NR_rt_sigreturn;
|
|
data[5] = 0xe93d;
|
|
|
|
/* Map to userspace with appropriate permissions (no write access...) */
|
|
cris_signal_return_page = (unsigned long)
|
|
__ioremap_prot(virt_to_phys(data), PAGE_SIZE, PAGE_SIGNAL_TRAMPOLINE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
__initcall(cris_init_signal);
|