summaryrefslogtreecommitdiff
path: root/arch/mips/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/signal.c')
-rw-r--r--arch/mips/kernel/signal.c54
1 files changed, 33 insertions, 21 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index f6efabcb4e92..4a10f18a8806 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -25,7 +25,7 @@
#include <linux/compiler.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
-#include <linux/tracehook.h>
+#include <linux/resume_user_mode.h>
#include <asm/abi.h>
#include <asm/asm.h>
@@ -35,10 +35,10 @@
#include <asm/sim.h>
#include <asm/ucontext.h>
#include <asm/cpu-features.h>
-#include <asm/war.h>
#include <asm/dsp.h>
#include <asm/inst.h>
#include <asm/msa.h>
+#include <asm/syscalls.h>
#include "signal-common.h"
@@ -52,7 +52,7 @@ struct sigframe {
/* Matches struct ucontext from its uc_mcontext field onwards */
struct sigcontext sf_sc;
sigset_t sf_mask;
- unsigned long long sf_extcontext[0];
+ unsigned long long sf_extcontext[];
};
struct rt_sigframe {
@@ -545,6 +545,12 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
return err ?: protected_restore_fp_context(sc);
}
+#ifdef CONFIG_WAR_ICACHE_REFILLS
+#define SIGMASK ~(cpu_icache_line_size()-1)
+#else
+#define SIGMASK ALMASK
+#endif
+
void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
size_t frame_size)
{
@@ -557,7 +563,14 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
sp = regs->regs[29];
/*
- * FPU emulator may have it's own trampoline active just
+ * If we are on the alternate signal stack and would overflow it, don't.
+ * Return an always-bogus address instead so we will die with SIGSEGV.
+ */
+ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
+ return (void __user __force *)(-1UL);
+
+ /*
+ * FPU emulator may have its own trampoline active just
* above the user stack, 16-bytes before the next lowest
* 16 byte boundary. Try to avoid trashing it.
*/
@@ -565,7 +578,7 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
sp = sigsp(sp, ksig);
- return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK));
+ return (void __user *)((sp - frame_size) & SIGMASK);
}
/*
@@ -741,23 +754,25 @@ static int setup_rt_frame(void *sig_return, struct ksignal *ksig,
struct pt_regs *regs, sigset_t *set)
{
struct rt_sigframe __user *frame;
- int err = 0;
frame = get_sigframe(ksig, regs, sizeof(*frame));
if (!access_ok(frame, sizeof (*frame)))
return -EFAULT;
/* Create siginfo. */
- err |= copy_siginfo_to_user(&frame->rs_info, &ksig->info);
+ if (copy_siginfo_to_user(&frame->rs_info, &ksig->info))
+ return -EFAULT;
/* Create the ucontext. */
- err |= __put_user(0, &frame->rs_uc.uc_flags);
- err |= __put_user(NULL, &frame->rs_uc.uc_link);
- err |= __save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
- err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
- err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
-
- if (err)
+ if (__put_user(0, &frame->rs_uc.uc_flags))
+ return -EFAULT;
+ if (__put_user(NULL, &frame->rs_uc.uc_link))
+ return -EFAULT;
+ if (__save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]))
+ return -EFAULT;
+ if (setup_sigcontext(regs, &frame->rs_uc.uc_mcontext))
+ return -EFAULT;
+ if (__copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)))
return -EFAULT;
/*
@@ -824,7 +839,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
regs->regs[2] = EINTR;
break;
}
- /* fallthrough */
+ fallthrough;
case ERESTARTNOINTR:
regs->regs[7] = regs->regs[26];
regs->regs[2] = regs->regs[0];
@@ -897,14 +912,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
uprobe_notify_resume(regs);
/* deal with pending signal delivery */
- if (thread_info_flags & _TIF_SIGPENDING)
+ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL))
do_signal(regs);
- if (thread_info_flags & _TIF_NOTIFY_RESUME) {
- clear_thread_flag(TIF_NOTIFY_RESUME);
- tracehook_notify_resume(regs);
- rseq_handle_notify_resume(NULL, regs);
- }
+ if (thread_info_flags & _TIF_NOTIFY_RESUME)
+ resume_user_mode_work(regs);
user_enter();
}