summaryrefslogtreecommitdiff
path: root/arch/sh/kernel/traps_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/traps_32.c')
-rw-r--r--arch/sh/kernel/traps_32.c77
1 files changed, 38 insertions, 39 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 57cff00cad17..1271b839a107 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* 'traps.c' handles hardware traps and faults after we have saved some
* state in 'entry.S'.
@@ -6,10 +7,6 @@
* Copyright (C) 2000 Philipp Rumpf
* Copyright (C) 2000 David Howells
* Copyright (C) 2002 - 2010 Paul Mundt
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/ptrace.h>
@@ -30,6 +27,7 @@
#include <asm/alignment.h>
#include <asm/fpu.h>
#include <asm/kprobes.h>
+#include <asm/setup.h>
#include <asm/traps.h>
#include <asm/bl_bit.h>
@@ -78,6 +76,23 @@ static struct mem_access user_mem_access = {
copy_to_user,
};
+static unsigned long copy_from_kernel_wrapper(void *dst, const void __user *src,
+ unsigned long cnt)
+{
+ return copy_from_kernel_nofault(dst, (const void __force *)src, cnt);
+}
+
+static unsigned long copy_to_kernel_wrapper(void __user *dst, const void *src,
+ unsigned long cnt)
+{
+ return copy_to_kernel_nofault((void __force *)dst, src, cnt);
+}
+
+static struct mem_access kernel_mem_access = {
+ copy_from_kernel_wrapper,
+ copy_to_kernel_wrapper,
+};
+
/*
* handle an instruction that does an unaligned memory access by emulating the
* desired behaviour
@@ -476,8 +491,6 @@ asmlinkage void do_address_error(struct pt_regs *regs,
unsigned long address)
{
unsigned long error_code = 0;
- mm_segment_t oldfs;
- siginfo_t info;
insn_size_t instruction;
int tmp;
@@ -486,8 +499,6 @@ asmlinkage void do_address_error(struct pt_regs *regs,
error_code = lookup_exception_vector();
#endif
- oldfs = get_fs();
-
if (user_mode(regs)) {
int si_code = BUS_ADRERR;
unsigned int user_action;
@@ -495,13 +506,10 @@ asmlinkage void do_address_error(struct pt_regs *regs,
local_irq_enable();
inc_unaligned_user_access();
- set_fs(USER_DS);
- if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1),
+ if (copy_from_user(&instruction, (insn_size_t __user *)(regs->pc & ~1),
sizeof(instruction))) {
- set_fs(oldfs);
goto uspace_segv;
}
- set_fs(oldfs);
/* shout about userspace fixups */
unaligned_fixups_notify(current, instruction, regs);
@@ -524,11 +532,9 @@ fixup:
goto uspace_segv;
}
- set_fs(USER_DS);
tmp = handle_unaligned_access(instruction, regs,
&user_mem_access, 0,
address);
- set_fs(oldfs);
if (tmp == 0)
return; /* sorted */
@@ -537,32 +543,25 @@ uspace_segv:
"access (PC %lx PR %lx)\n", current->comm, regs->pc,
regs->pr);
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = si_code;
- info.si_addr = (void __user *)address;
- force_sig_info(SIGBUS, &info, current);
+ force_sig_fault(SIGBUS, si_code, (void __user *)address);
} else {
inc_unaligned_kernel_access();
if (regs->pc & 1)
die("unaligned program counter", regs, error_code);
- set_fs(KERNEL_DS);
- if (copy_from_user(&instruction, (void __user *)(regs->pc),
+ if (copy_from_kernel_nofault(&instruction, (void *)(regs->pc),
sizeof(instruction))) {
/* Argh. Fault on the instruction itself.
This should never happen non-SMP
*/
- set_fs(oldfs);
die("insn faulting in do_address_error", regs, 0);
}
unaligned_fixups_notify(current, instruction, regs);
- handle_unaligned_access(instruction, regs, &user_mem_access,
+ handle_unaligned_access(instruction, regs, &kernel_mem_access,
0, address);
- set_fs(oldfs);
}
}
@@ -570,7 +569,7 @@ uspace_segv:
/*
* SH-DSP support gerg@snapgear.com.
*/
-int is_dsp_inst(struct pt_regs *regs)
+static int is_dsp_inst(struct pt_regs *regs)
{
unsigned short inst = 0;
@@ -592,24 +591,26 @@ int is_dsp_inst(struct pt_regs *regs)
return 0;
}
#else
-#define is_dsp_inst(regs) (0)
+static inline int is_dsp_inst(struct pt_regs *regs) { return 0; }
#endif /* CONFIG_SH_DSP */
#ifdef CONFIG_CPU_SH2A
asmlinkage void do_divide_error(unsigned long r4)
{
- siginfo_t info;
+ int code;
switch (r4) {
case TRAP_DIVZERO_ERROR:
- info.si_code = FPE_INTDIV;
+ code = FPE_INTDIV;
break;
case TRAP_DIVOVF_ERROR:
- info.si_code = FPE_INTOVF;
+ code = FPE_INTOVF;
break;
+ default:
+ /* Let gcc know unhandled cases don't make it past here */
+ return;
}
-
- force_sig_info(SIGFPE, &info, current);
+ force_sig_fault(SIGFPE, code, NULL);
}
#endif
@@ -617,13 +618,12 @@ asmlinkage void do_reserved_inst(void)
{
struct pt_regs *regs = current_pt_regs();
unsigned long error_code;
- struct task_struct *tsk = current;
#ifdef CONFIG_SH_FPU_EMU
unsigned short inst = 0;
int err;
- get_user(inst, (unsigned short*)regs->pc);
+ get_user(inst, (unsigned short __user *)regs->pc);
err = do_fpu_inst(inst, regs);
if (!err) {
@@ -639,7 +639,7 @@ asmlinkage void do_reserved_inst(void)
/* Enable DSP mode, and restart instruction. */
regs->sr |= SR_DSP;
/* Save DSP mode */
- tsk->thread.dsp_status.status |= SR_DSP;
+ current->thread.dsp_status.status |= SR_DSP;
return;
}
#endif
@@ -647,7 +647,7 @@ asmlinkage void do_reserved_inst(void)
error_code = lookup_exception_vector();
local_irq_enable();
- force_sig(SIGILL, tsk);
+ force_sig(SIGILL);
die_if_no_fixup("reserved instruction", regs, error_code);
}
@@ -703,15 +703,14 @@ asmlinkage void do_illegal_slot_inst(void)
{
struct pt_regs *regs = current_pt_regs();
unsigned long inst;
- struct task_struct *tsk = current;
if (kprobe_handle_illslot(regs->pc) == 0)
return;
#ifdef CONFIG_SH_FPU_EMU
- get_user(inst, (unsigned short *)regs->pc + 1);
+ get_user(inst, (unsigned short __user *)regs->pc + 1);
if (!do_fpu_inst(inst, regs)) {
- get_user(inst, (unsigned short *)regs->pc);
+ get_user(inst, (unsigned short __user *)regs->pc);
if (!emulate_branch(inst, regs))
return;
/* fault in branch.*/
@@ -722,7 +721,7 @@ asmlinkage void do_illegal_slot_inst(void)
inst = lookup_exception_vector();
local_irq_enable();
- force_sig(SIGILL, tsk);
+ force_sig(SIGILL);
die_if_no_fixup("illegal slot instruction", regs, inst);
}