Commit b5a1bcbe authored by Stuart Menefy's avatar Stuart Menefy Committed by Paul Mundt

sh: Set up correct siginfo structures for page faults.

Remove the previous saving of fault codes into the thread_struct
as they are never used, and appeared to be inherited from x86.
Signed-off-by: default avatarStuart Menefy <stuart.menefy@st.com>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent f0bc814c
...@@ -282,11 +282,8 @@ ieee_fpe_handler (struct pt_regs *regs) ...@@ -282,11 +282,8 @@ ieee_fpe_handler (struct pt_regs *regs)
grab_fpu(regs); grab_fpu(regs);
restore_fpu(tsk); restore_fpu(tsk);
set_tsk_thread_flag(tsk, TIF_USEDFPU); set_tsk_thread_flag(tsk, TIF_USEDFPU);
} else { } else
tsk->thread.trap_no = 11;
tsk->thread.error_code = 0;
force_sig(SIGFPE, tsk); force_sig(SIGFPE, tsk);
}
regs->pc = nextpc; regs->pc = nextpc;
return 1; return 1;
...@@ -307,8 +304,6 @@ do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, ...@@ -307,8 +304,6 @@ do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6,
regs->pc += 2; regs->pc += 2;
save_fpu(tsk, regs); save_fpu(tsk, regs);
tsk->thread.trap_no = 11;
tsk->thread.error_code = 0;
force_sig(SIGFPE, tsk); force_sig(SIGFPE, tsk);
} }
......
...@@ -93,7 +93,7 @@ void die(const char * str, struct pt_regs * regs, long err) ...@@ -93,7 +93,7 @@ void die(const char * str, struct pt_regs * regs, long err)
if (!user_mode(regs) || in_interrupt()) if (!user_mode(regs) || in_interrupt())
dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
(unsigned long)task_stack_page(current)); (unsigned long)task_stack_page(current));
bust_spinlocks(0); bust_spinlocks(0);
spin_unlock_irq(&die_lock); spin_unlock_irq(&die_lock);
...@@ -201,7 +201,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) ...@@ -201,7 +201,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
if (copy_to_user(dst,src,4)) if (copy_to_user(dst,src,4))
goto fetch_fault; goto fetch_fault;
ret = 0; ret = 0;
break; break;
case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
if (instruction & 4) if (instruction & 4)
...@@ -225,7 +225,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) ...@@ -225,7 +225,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
if (copy_from_user(dst,src,4)) if (copy_from_user(dst,src,4))
goto fetch_fault; goto fetch_fault;
ret = 0; ret = 0;
break; break;
case 6: /* mov.[bwl] from memory, possibly with post-increment */ case 6: /* mov.[bwl] from memory, possibly with post-increment */
src = (unsigned char*) *rm; src = (unsigned char*) *rm;
...@@ -233,7 +233,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) ...@@ -233,7 +233,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
*rm += count; *rm += count;
dst = (unsigned char*) rn; dst = (unsigned char*) rn;
*(unsigned long*)dst = 0; *(unsigned long*)dst = 0;
#ifdef __LITTLE_ENDIAN__ #ifdef __LITTLE_ENDIAN__
if (copy_from_user(dst, src, count)) if (copy_from_user(dst, src, count))
goto fetch_fault; goto fetch_fault;
...@@ -244,7 +244,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) ...@@ -244,7 +244,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
} }
#else #else
dst += 4-count; dst += 4-count;
if (copy_from_user(dst, src, count)) if (copy_from_user(dst, src, count))
goto fetch_fault; goto fetch_fault;
...@@ -323,7 +323,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) ...@@ -323,7 +323,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs)
return -EFAULT; return -EFAULT;
/* kernel */ /* 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); return handle_unaligned_ins(instruction,regs);
...@@ -364,7 +365,8 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *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) { if (user_mode(regs) && handle_unaligned_notify_count>0) {
handle_unaligned_notify_count--; 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); current->comm,current->pid,(u16*)regs->pc,instruction);
} }
...@@ -499,7 +501,15 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) ...@@ -499,7 +501,15 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
#endif #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, asmlinkage void do_address_error(struct pt_regs *regs,
unsigned long writeaccess, unsigned long writeaccess,
...@@ -507,6 +517,7 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -507,6 +517,7 @@ asmlinkage void do_address_error(struct pt_regs *regs,
{ {
unsigned long error_code = 0; unsigned long error_code = 0;
mm_segment_t oldfs; mm_segment_t oldfs;
siginfo_t info;
#ifndef CONFIG_CPU_SH2A #ifndef CONFIG_CPU_SH2A
u16 instruction; u16 instruction;
int tmp; int tmp;
...@@ -520,22 +531,15 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -520,22 +531,15 @@ asmlinkage void do_address_error(struct pt_regs *regs,
oldfs = get_fs(); oldfs = get_fs();
if (user_mode(regs)) { if (user_mode(regs)) {
int si_code = BUS_ADRERR;
local_irq_enable(); 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 */ /* bad PC is not something we can fix */
if (regs->pc & 1) if (regs->pc & 1) {
si_code = BUS_ADRALN;
goto uspace_segv; goto uspace_segv;
}
#ifndef CONFIG_CPU_SH2A #ifndef CONFIG_CPU_SH2A
set_fs(USER_DS); set_fs(USER_DS);
...@@ -554,9 +558,16 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -554,9 +558,16 @@ asmlinkage void do_address_error(struct pt_regs *regs,
return; /* sorted */ return; /* sorted */
#endif #endif
uspace_segv: uspace_segv:
printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm); printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
force_sig(SIGSEGV, current); "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 { } else {
if (regs->pc & 1) if (regs->pc & 1)
die("unaligned program counter", regs, error_code); die("unaligned program counter", regs, error_code);
...@@ -574,7 +585,9 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -574,7 +585,9 @@ asmlinkage void do_address_error(struct pt_regs *regs,
handle_unaligned_access(instruction, regs); handle_unaligned_access(instruction, regs);
set_fs(oldfs); set_fs(oldfs);
#else #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); force_sig(SIGSEGV, current);
#endif #endif
} }
...@@ -617,9 +630,6 @@ asmlinkage void do_divide_error(unsigned long r4, unsigned long r5, ...@@ -617,9 +630,6 @@ asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
struct pt_regs *regs = RELOC_HIDE(&__regs, 0); struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
siginfo_t info; siginfo_t info;
current->thread.trap_no = r4;
current->thread.error_code = 0;
switch (r4) { switch (r4) {
case TRAP_DIVZERO_ERROR: case TRAP_DIVZERO_ERROR:
info.si_code = FPE_INTDIV; info.si_code = FPE_INTDIV;
...@@ -662,7 +672,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, ...@@ -662,7 +672,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
#ifdef CONFIG_SH_DSP #ifdef CONFIG_SH_DSP
/* Check if it's a DSP instruction */ /* Check if it's a DSP instruction */
if (is_dsp_inst(regs)) { if (is_dsp_inst(regs)) {
/* Enable DSP mode, and restart instruction. */ /* Enable DSP mode, and restart instruction. */
regs->sr |= SR_DSP; regs->sr |= SR_DSP;
return; return;
...@@ -672,8 +682,6 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, ...@@ -672,8 +682,6 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
lookup_exception_vector(error_code); lookup_exception_vector(error_code);
local_irq_enable(); local_irq_enable();
tsk->thread.error_code = error_code;
tsk->thread.trap_no = TRAP_RESERVED_INST;
CHK_REMOTE_DEBUG(regs); CHK_REMOTE_DEBUG(regs);
force_sig(SIGILL, tsk); force_sig(SIGILL, tsk);
die_if_no_fixup("reserved instruction", regs, error_code); 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, ...@@ -745,8 +753,6 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
lookup_exception_vector(error_code); lookup_exception_vector(error_code);
local_irq_enable(); local_irq_enable();
tsk->thread.error_code = error_code;
tsk->thread.trap_no = TRAP_RESERVED_INST;
CHK_REMOTE_DEBUG(regs); CHK_REMOTE_DEBUG(regs);
force_sig(SIGILL, tsk); force_sig(SIGILL, tsk);
die_if_no_fixup("illegal slot instruction", regs, error_code); die_if_no_fixup("illegal slot instruction", regs, error_code);
...@@ -805,7 +811,7 @@ void *set_exception_table_vec(unsigned int vec, void *handler) ...@@ -805,7 +811,7 @@ void *set_exception_table_vec(unsigned int vec, void *handler)
{ {
extern void *exception_handling_table[]; extern void *exception_handling_table[];
void *old_handler; void *old_handler;
old_handler = exception_handling_table[vec]; old_handler = exception_handling_table[vec];
exception_handling_table[vec] = handler; exception_handling_table[vec] = handler;
return old_handler; return old_handler;
...@@ -841,7 +847,7 @@ void __init trap_init(void) ...@@ -841,7 +847,7 @@ void __init trap_init(void)
set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error); set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error); set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
#endif #endif
/* Setup VBR for boot cpu */ /* Setup VBR for boot cpu */
per_cpu_trap_init(); per_cpu_trap_init();
} }
......
...@@ -26,13 +26,16 @@ extern void die(const char *,struct pt_regs *,long); ...@@ -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 * and the problem, and then passes it off to one of the appropriate
* routines. * routines.
*/ */
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
unsigned long address) unsigned long writeaccess,
unsigned long address)
{ {
struct task_struct *tsk; struct task_struct *tsk;
struct mm_struct *mm; struct mm_struct *mm;
struct vm_area_struct * vma; struct vm_area_struct * vma;
unsigned long page; unsigned long page;
int si_code;
siginfo_t info;
#ifdef CONFIG_SH_KGDB #ifdef CONFIG_SH_KGDB
if (kgdb_nofault && kgdb_bus_err_hook) if (kgdb_nofault && kgdb_bus_err_hook)
...@@ -41,6 +44,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, ...@@ -41,6 +44,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
tsk = current; tsk = current;
mm = tsk->mm; mm = tsk->mm;
si_code = SEGV_MAPERR;
/* /*
* If we're in an interrupt or have no user * 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, ...@@ -65,6 +69,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
* we can handle it.. * we can handle it..
*/ */
good_area: good_area:
si_code = SEGV_ACCERR;
if (writeaccess) { if (writeaccess) {
if (!(vma->vm_flags & VM_WRITE)) if (!(vma->vm_flags & VM_WRITE))
goto bad_area; goto bad_area;
...@@ -105,9 +110,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, ...@@ -105,9 +110,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
if (user_mode(regs)) { if (user_mode(regs)) {
tsk->thread.address = address; info.si_signo = SIGSEGV;
tsk->thread.error_code = writeaccess; info.si_errno = 0;
force_sig(SIGSEGV, tsk); info.si_code = si_code;
info.si_addr = (void *) address;
force_sig_info(SIGSEGV, &info, tsk);
return; return;
} }
...@@ -166,10 +173,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, ...@@ -166,10 +173,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
* Send a sigbus, regardless of whether we were in kernel * Send a sigbus, regardless of whether we were in kernel
* or user mode. * or user mode.
*/ */
tsk->thread.address = address; info.si_signo = SIGBUS;
tsk->thread.error_code = writeaccess; info.si_errno = 0;
tsk->thread.trap_no = 14; info.si_code = BUS_ADRERR;
force_sig(SIGBUS, tsk); info.si_addr = (void *)address;
force_sig_info(SIGBUS, &info, tsk);
/* Kernel mode? Handle exceptions or die */ /* Kernel mode? Handle exceptions or die */
if (!user_mode(regs)) if (!user_mode(regs))
......
...@@ -136,12 +136,11 @@ union sh_fpu_union { ...@@ -136,12 +136,11 @@ union sh_fpu_union {
}; };
struct thread_struct { struct thread_struct {
/* Saved registers when thread is descheduled */
unsigned long sp; unsigned long sp;
unsigned long pc; unsigned long pc;
unsigned long trap_no, error_code; /* Hardware debugging registers */
unsigned long address;
/* Hardware debugging registers may come here */
unsigned long ubc_pc; unsigned long ubc_pc;
/* floating point info */ /* floating point info */
...@@ -156,12 +155,7 @@ typedef struct { ...@@ -156,12 +155,7 @@ typedef struct {
extern int ubc_usercnt; extern int ubc_usercnt;
#define INIT_THREAD { \ #define INIT_THREAD { \
sizeof(init_stack) + (long) &init_stack, /* sp */ \ .sp = sizeof(init_stack) + (long) &init_stack, \
0, /* pc */ \
0, 0, \
0, \
0, \
{{{0,}},} /* fpu state */ \
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment