/* * arch/xtensa/kernel/signal.c * * Default platform functions. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2005, 2006 Tensilica Inc. * Copyright (C) 1991, 1992 Linus Torvalds * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * * Chris Zankel <chris@zankel.net> * Joe Taylor <joe@tensilica.com>
*/
/* * Note: We don't copy double exception 'regs', we have to finish double exc. * first before we return to signal handler! This dbl.exc.handler might cause * another double exception, but I think we are fine as the situation is the * same as if we had returned to the signal handerl and got an interrupt * immediately...
*/
/* For PS, restore only PS.CALLINC. * Assume that all other bits are either the same as for the signal * handler, or the user mode value doesn't matter (e.g. PS.OWB).
*/
err |= __get_user(ps, &sc->sc_ps);
regs->ps = (regs->ps & ~PS_CALLINC_MASK) | (ps & PS_CALLINC_MASK);
/* The signal handler may have used coprocessors in which * case they are still enabled. We disable them to force a * reloading of the original task's CP state by the lazy * context-switching mechanisms of CP exception handling. * Also, we essentially discard any coprocessor state that the
* signal handler created. */
if (!access_ok(frame, sizeof(*frame))) goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe;
set_current_blocked(&set);
if (restore_sigcontext(regs, frame)) goto badframe;
ret = regs->areg[2];
if (restore_altstack(&frame->uc.uc_stack)) goto badframe;
return ret;
badframe:
force_sig(SIGSEGV); return 0;
}
/* * Set up a signal frame.
*/
staticint
gen_return_code(unsignedchar *codemem)
{ int err = 0;
/* * The 12-bit immediate is really split up within the 24-bit MOVI * instruction. As long as the above system call numbers fit within * 8-bits, the following code works fine. See the Xtensa ISA for * details.
*/
/* Create sys_rt_sigreturn syscall in stack frame */
err |= gen_return_code(frame->retcode);
ra = (unsignedlong) frame->retcode;
}
if (err) return -EFAULT;
/* * Create signal handler execution context. * Return context not modified until this point.
*/
/* Set up registers for signal handler; preserve the threadptr */
tp = regs->threadptr;
ps = regs->ps;
start_thread(regs, handler, (unsignedlong)frame);
/* Set up a stack frame for a call4 if userspace uses windowed ABI */ if (ps & PS_WOE_MASK) {
base = 4;
regs->areg[base] =
(((unsignedlong) ra) & 0x3fffffff) | 0x40000000;
ps = (ps & ~(PS_CALLINC_MASK | PS_OWB_MASK)) |
(1 << PS_CALLINC_SHIFT);
} else {
base = 0;
regs->areg[base] = (unsignedlong) ra;
}
regs->areg[base + 2] = (unsignedlong) sig;
regs->areg[base + 3] = (unsignedlong) &frame->info;
regs->areg[base + 4] = (unsignedlong) &frame->uc;
regs->threadptr = tp;
regs->ps = ps; if (fdpic)
regs->areg[base + 11] = handler_fdpic_GOT;
/* * 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. * * Note that we go through the signals twice: once to check the signals that * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that.
*/ staticvoid do_signal(struct pt_regs *regs)
{ struct ksignal ksig;
task_pt_regs(current)->icountlevel = 0;
if (get_signal(&ksig)) { int ret;
/* Are we from a system call? */
if (regs->syscall != NO_SYSCALL) {
/* If so, check system call restarting.. */
switch (regs->areg[2]) { case -ERESTARTNOHAND: case -ERESTART_RESTARTBLOCK:
regs->areg[2] = -EINTR; break;
case -ERESTARTSYS: if (!(ksig.ka.sa.sa_flags & SA_RESTART)) {
regs->areg[2] = -EINTR; break;
}
fallthrough; case -ERESTARTNOINTR:
regs->areg[2] = regs->syscall;
regs->pc -= 3; break;
default: /* nothing to do */ if (regs->areg[2] != 0) break;
}
}
/* Whee! Actually deliver the signal. */ /* Set up the stack frame */
ret = setup_frame(&ksig, sigmask_to_save(), regs);
signal_setup_done(ret, &ksig, 0); if (test_thread_flag(TIF_SINGLESTEP))
task_pt_regs(current)->icountlevel = 1;
return;
}
/* Did we come from a system call? */ if (regs->syscall != NO_SYSCALL) { /* Restart the system call - no handlers present */ switch (regs->areg[2]) { case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR:
regs->areg[2] = regs->syscall;
regs->pc -= 3; break; case -ERESTART_RESTARTBLOCK:
regs->areg[2] = __NR_restart_syscall;
regs->pc -= 3; break;
}
}
/* If there's no signal to deliver, we just restore the saved mask. */
restore_saved_sigmask();
if (test_thread_flag(TIF_SINGLESTEP))
task_pt_regs(current)->icountlevel = 1; return;
}
void do_notify_resume(struct pt_regs *regs)
{ if (test_thread_flag(TIF_SIGPENDING) ||
test_thread_flag(TIF_NOTIFY_SIGNAL))
do_signal(regs);
if (test_thread_flag(TIF_NOTIFY_RESUME))
resume_user_mode_work(regs);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.