sh: Set up correct siginfo structures for page faults.
authorStuart Menefy <stuart.menefy@st.com>
Tue, 21 Nov 2006 04:34:04 +0000 (13:34 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 6 Dec 2006 01:45:38 +0000 (10:45 +0900)
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>
arch/sh/kernel/cpu/sh4/fpu.c
arch/sh/kernel/traps.c
arch/sh/mm/fault.c
include/asm-sh/processor.h

index 378b488237c9cfee34f36ba52d4b77b22afb2890..7624677f66281e7ef31b99d9b48caf1bc7534b5d 100644 (file)
@@ -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);
 }
 
index b52037bc1255650193dd56c6ed44f7017e57e0bb..0ee298079d827134c1f6ad9aaa7ae8e7ffee2173 100644 (file)
@@ -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();
 }
index 68663b8f99aec28619ea7cb92d16978c5a08be25..43bed2cb00e38c73c0c10a8e78e405477f7c6faa 100644 (file)
@@ -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))
index da22ac30c75f118e823293586b9fc5653b559e77..4a90e7cd81992faa0c37bcdb56d8e8027d59819a 100644 (file)
@@ -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,          \
 }
 
 /*