summaryrefslogtreecommitdiff
path: root/arch/cris/arch-v32/kernel/signal.c
diff options
context:
space:
mode:
authorJesper Nilsson <jesper@jni.nu>2018-03-11 11:05:23 +0100
committerArnd Bergmann <arnd@arndb.de>2018-03-16 10:56:05 +0100
commitc690eddc2f3b44b24520f4a77cc3a4c9bde7d571 (patch)
treeb7ba2caa6ebb2e36a529f9bf7182c9e0a73d53c4 /arch/cris/arch-v32/kernel/signal.c
parentbb9d812643d8a121df7d614a2b9c60193a92deb0 (diff)
CRIS: Drop support for the CRIS port
The port was added back in 2000 so it's no longer even a good source of inspiration for newer ports (if it ever was) The last SoC (ARTPEC-3) with a CRIS main CPU was launched in 2008. Coupled with time and working developer board hardware being in low supply, it's time to drop the port from Linux. So long and thanks for all the fish! Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/cris/arch-v32/kernel/signal.c')
-rw-r--r--arch/cris/arch-v32/kernel/signal.c541
1 files changed, 0 insertions, 541 deletions
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c
deleted file mode 100644
index 4f2e3ba3bf40..000000000000
--- a/arch/cris/arch-v32/kernel/signal.c
+++ /dev/null
@@ -1,541 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2003, Axis Communications AB.
- */
-
-#include <linux/sched.h>
-#include <linux/sched/task_stack.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 <linux/uaccess.h>
-#include <arch/hwregs/cpu_vect.h>
-
-extern unsigned long cris_signal_return_page;
-
-/*
- * 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);
-
-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->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));
-
- /* Don't perform syscall restarting */
- regs->exs = -1;
-
- /* Restore the old USP. */
- err |= __get_user(old_usp, &sc->usp);
- wrusp(old_usp);
-
- return err;
-
-badframe:
- return 1;
-}
-
-asmlinkage int sys_sigreturn(void)
-{
- struct pt_regs *regs = current_pt_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;
-
- set_current_blocked(&set);
-
- if (restore_sigcontext(regs, &frame->sc))
- goto badframe;
-
- keep_debug_flags(oldccs, oldspc, regs);
-
- return regs->r10;
-
-badframe:
- force_sig(SIGSEGV, current);
- return 0;
-}
-
-asmlinkage int sys_rt_sigreturn(void)
-{
- struct pt_regs *regs = current_pt_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;
-
- set_current_blocked(&set);
-
- if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
- goto badframe;
-
- if (restore_altstack(&frame->uc.uc_stack))
- 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 ksignal *ksig, size_t frame_size)
-{
- unsigned long sp = sigsp(rdusp(), ksig);
-
- /* 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(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
-{
- int err;
- unsigned long return_ip;
- struct signal_frame __user *frame;
-
- err = 0;
- frame = get_sigframe(ksig, sizeof(*frame));
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- return -EFAULT;
-
- err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
-
- if (err)
- return -EFAULT;
-
- if (_NSIG_WORDS > 1) {
- err |= __copy_to_user(frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
- }
-
- if (err)
- return -EFAULT;
-
- /*
- * Set up to return from user-space. If provided, use a stub
- * already located in user-space.
- */
- if (ksig->ka.sa.sa_flags & SA_RESTORER) {
- return_ip = (unsigned long)ksig->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)
- return -EFAULT;
-
- /*
- * Set up registers for signal handler.
- *
- * Where the code enters now.
- * Where the code enter later.
- * First argument, signo.
- */
- regs->erp = (unsigned long) ksig->ka.sa.sa_handler;
- regs->srp = return_ip;
- regs->r10 = ksig->sig;
-
- /* Actually move the USP to reflect the stacked frame. */
- wrusp((unsigned long)frame);
-
- return 0;
-}
-
-static int
-setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
-{
- int err;
- unsigned long return_ip;
- struct rt_signal_frame __user *frame;
-
- err = 0;
- frame = get_sigframe(ksig, sizeof(*frame));
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- return -EFAULT;
-
- err |= __put_user(&frame->info, &frame->pinfo);
- err |= __put_user(&frame->uc, &frame->puc);
- err |= copy_siginfo_to_user(&frame->info, &ksig->info);
-
- if (err)
- return -EFAULT;
-
- /* 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));
- err |= __save_altstack(&frame->uc.uc_stack, rdusp());
-
- if (err)
- return -EFAULT;
-
- /*
- * Set up to return from user-space. If provided, use a stub
- * already located in user-space.
- */
- if (ksig->ka.sa.sa_flags & SA_RESTORER) {
- return_ip = (unsigned long) ksig->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)
- return -EFAULT;
-
- /*
- * 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) ksig->ka.sa.sa_handler;
- regs->srp = return_ip;
- regs->r10 = ksig->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;
-}
-
-/* Invoke a signal handler to, well, handle the signal. */
-static inline void
-handle_signal(int canrestart, struct ksignal *ksig, struct pt_regs *regs)
-{
- sigset_t *oldset = sigmask_to_save();
- 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 (!(ksig->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 (ksig->ka.sa.sa_flags & SA_SIGINFO)
- ret = setup_rt_frame(ksig, oldset, regs);
- else
- ret = setup_frame(ksig, oldset, regs);
-
- signal_setup_done(ret, ksig, 0);
-}
-
-/*
- * 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)
-{
- struct ksignal ksig;
-
- canrestart = canrestart && ((int)regs->exs >= 0);
-
- /*
- * 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 (get_signal(&ksig)) {
- /* Whee! Actually deliver the signal. */
- handle_signal(canrestart, &ksig, regs);
- 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->r9 = __NR_restart_syscall;
- regs->erp -= 2;
- }
- }
-
- /* if there's no signal to deliver, we just put the saved sigmask
- * back */
- restore_saved_sigmask();
-}
-
-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 within 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);