forked from luck/tmp_suning_uos_patched
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: Stuart Menefy <stuart.menefy@st.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
parent
f0bc814cfb
commit
b5a1bcbee4
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
|
||||
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 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
|
||||
* 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))
|
||||
|
@ -136,12 +136,11 @@ union sh_fpu_union {
|
||||
};
|
||||
|
||||
struct thread_struct {
|
||||
/* Saved registers when thread is descheduled */
|
||||
unsigned long sp;
|
||||
unsigned long pc;
|
||||
|
||||
unsigned long trap_no, error_code;
|
||||
unsigned long address;
|
||||
/* Hardware debugging registers may come here */
|
||||
/* Hardware debugging registers */
|
||||
unsigned long ubc_pc;
|
||||
|
||||
/* floating point info */
|
||||
@ -156,12 +155,7 @@ typedef struct {
|
||||
extern int ubc_usercnt;
|
||||
|
||||
#define INIT_THREAD { \
|
||||
sizeof(init_stack) + (long) &init_stack, /* sp */ \
|
||||
0, /* pc */ \
|
||||
0, 0, \
|
||||
0, \
|
||||
0, \
|
||||
{{{0,}},} /* fpu state */ \
|
||||
.sp = sizeof(init_stack) + (long) &init_stack, \
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user