summaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/kernel/cpu/sh4/fpu.c7
-rw-r--r--arch/sh/kernel/traps.c74
-rw-r--r--arch/sh/mm/fault.c26
3 files changed, 58 insertions, 49 deletions
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index 378b488237c9..7624677f6628 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -282,11 +282,8 @@ ieee_fpe_handler (struct pt_regs *regs)
grab_fpu(regs);
restore_fpu(tsk);
set_tsk_thread_flag(tsk, TIF_USEDFPU);
- } else {
- tsk->thread.trap_no = 11;
- tsk->thread.error_code = 0;
+ } else
force_sig(SIGFPE, tsk);
- }
regs->pc = nextpc;
return 1;
@@ -307,8 +304,6 @@ do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6,
regs->pc += 2;
save_fpu(tsk, regs);
- tsk->thread.trap_no = 11;
- tsk->thread.error_code = 0;
force_sig(SIGFPE, tsk);
}
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index b52037bc1255..0ee298079d82 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -93,7 +93,7 @@ void die(const char * str, struct pt_regs * regs, long err)
if (!user_mode(regs) || in_interrupt())
dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
- (unsigned long)task_stack_page(current));
+ (unsigned long)task_stack_page(current));
bust_spinlocks(0);
spin_unlock_irq(&die_lock);
@@ -201,7 +201,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
if (copy_to_user(dst,src,4))
goto fetch_fault;
ret = 0;
- break;
+ break;
case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
if (instruction & 4)
@@ -225,7 +225,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
if (copy_from_user(dst,src,4))
goto fetch_fault;
ret = 0;
- break;
+ break;
case 6: /* mov.[bwl] from memory, possibly with post-increment */
src = (unsigned char*) *rm;
@@ -233,7 +233,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
*rm += count;
dst = (unsigned char*) rn;
*(unsigned long*)dst = 0;
-
+
#ifdef __LITTLE_ENDIAN__
if (copy_from_user(dst, src, count))
goto fetch_fault;
@@ -244,7 +244,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
}
#else
dst += 4-count;
-
+
if (copy_from_user(dst, src, count))
goto fetch_fault;
@@ -323,7 +323,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs)
return -EFAULT;
/* kernel */
- die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0);
+ die("delay-slot-insn faulting in handle_unaligned_delayslot",
+ regs, 0);
}
return handle_unaligned_ins(instruction,regs);
@@ -364,7 +365,8 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
if (user_mode(regs) && handle_unaligned_notify_count>0) {
handle_unaligned_notify_count--;
- printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
+ printk(KERN_NOTICE "Fixing up unaligned userspace access "
+ "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
current->comm,current->pid,(u16*)regs->pc,instruction);
}
@@ -499,7 +501,15 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
#endif
/*
- * Handle various address error exceptions
+ * Handle various address error exceptions:
+ * - instruction address error:
+ * misaligned PC
+ * PC >= 0x80000000 in user mode
+ * - data address error (read and write)
+ * misaligned data access
+ * access to >= 0x80000000 is user mode
+ * Unfortuntaly we can't distinguish between instruction address error
+ * and data address errors caused by read acceses.
*/
asmlinkage void do_address_error(struct pt_regs *regs,
unsigned long writeaccess,
@@ -507,6 +517,7 @@ asmlinkage void do_address_error(struct pt_regs *regs,
{
unsigned long error_code = 0;
mm_segment_t oldfs;
+ siginfo_t info;
#ifndef CONFIG_CPU_SH2A
u16 instruction;
int tmp;
@@ -520,22 +531,15 @@ asmlinkage void do_address_error(struct pt_regs *regs,
oldfs = get_fs();
if (user_mode(regs)) {
+ int si_code = BUS_ADRERR;
+
local_irq_enable();
- current->thread.error_code = error_code;
-#ifdef CONFIG_CPU_SH2
- /*
- * On the SH-2, we only have a single vector for address
- * errors, there's no differentiating between a load error
- * and a store error.
- */
- current->thread.trap_no = 9;
-#else
- current->thread.trap_no = (writeaccess) ? 8 : 7;
-#endif
/* bad PC is not something we can fix */
- if (regs->pc & 1)
+ if (regs->pc & 1) {
+ si_code = BUS_ADRALN;
goto uspace_segv;
+ }
#ifndef CONFIG_CPU_SH2A
set_fs(USER_DS);
@@ -554,9 +558,16 @@ asmlinkage void do_address_error(struct pt_regs *regs,
return; /* sorted */
#endif
- uspace_segv:
- printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm);
- force_sig(SIGSEGV, current);
+uspace_segv:
+ printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
+ "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 *) address;
+ force_sig_info(SIGBUS, &info, current);
} else {
if (regs->pc & 1)
die("unaligned program counter", regs, error_code);
@@ -574,7 +585,9 @@ asmlinkage void do_address_error(struct pt_regs *regs,
handle_unaligned_access(instruction, regs);
set_fs(oldfs);
#else
- printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm);
+ printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
+ "access\n", current->comm);
+
force_sig(SIGSEGV, current);
#endif
}
@@ -617,9 +630,6 @@ asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
siginfo_t info;
- current->thread.trap_no = r4;
- current->thread.error_code = 0;
-
switch (r4) {
case TRAP_DIVZERO_ERROR:
info.si_code = FPE_INTDIV;
@@ -662,7 +672,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
#ifdef CONFIG_SH_DSP
/* Check if it's a DSP instruction */
- if (is_dsp_inst(regs)) {
+ if (is_dsp_inst(regs)) {
/* Enable DSP mode, and restart instruction. */
regs->sr |= SR_DSP;
return;
@@ -672,8 +682,6 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
lookup_exception_vector(error_code);
local_irq_enable();
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = TRAP_RESERVED_INST;
CHK_REMOTE_DEBUG(regs);
force_sig(SIGILL, tsk);
die_if_no_fixup("reserved instruction", regs, error_code);
@@ -745,8 +753,6 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
lookup_exception_vector(error_code);
local_irq_enable();
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = TRAP_RESERVED_INST;
CHK_REMOTE_DEBUG(regs);
force_sig(SIGILL, tsk);
die_if_no_fixup("illegal slot instruction", regs, error_code);
@@ -805,7 +811,7 @@ void *set_exception_table_vec(unsigned int vec, void *handler)
{
extern void *exception_handling_table[];
void *old_handler;
-
+
old_handler = exception_handling_table[vec];
exception_handling_table[vec] = handler;
return old_handler;
@@ -841,7 +847,7 @@ void __init trap_init(void)
set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
#endif
-
+
/* Setup VBR for boot cpu */
per_cpu_trap_init();
}
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index 68663b8f99ae..43bed2cb00e3 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -26,13 +26,16 @@ extern void die(const char *,struct pt_regs *,long);
* and the problem, and then passes it off to one of the appropriate
* routines.
*/
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
- unsigned long address)
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+ unsigned long writeaccess,
+ unsigned long address)
{
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct * vma;
unsigned long page;
+ int si_code;
+ siginfo_t info;
#ifdef CONFIG_SH_KGDB
if (kgdb_nofault && kgdb_bus_err_hook)
@@ -41,6 +44,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
tsk = current;
mm = tsk->mm;
+ si_code = SEGV_MAPERR;
/*
* If we're in an interrupt or have no user
@@ -65,6 +69,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
* we can handle it..
*/
good_area:
+ si_code = SEGV_ACCERR;
if (writeaccess) {
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
@@ -105,9 +110,11 @@ bad_area:
up_read(&mm->mmap_sem);
if (user_mode(regs)) {
- tsk->thread.address = address;
- tsk->thread.error_code = writeaccess;
- force_sig(SIGSEGV, tsk);
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = si_code;
+ info.si_addr = (void *) address;
+ force_sig_info(SIGSEGV, &info, tsk);
return;
}
@@ -166,10 +173,11 @@ do_sigbus:
* Send a sigbus, regardless of whether we were in kernel
* or user mode.
*/
- tsk->thread.address = address;
- tsk->thread.error_code = writeaccess;
- tsk->thread.trap_no = 14;
- force_sig(SIGBUS, tsk);
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+ force_sig_info(SIGBUS, &info, tsk);
/* Kernel mode? Handle exceptions or die */
if (!user_mode(regs))