Merge to Fedora kernel-2.6.7-1.441
[linux-2.6.git] / arch / sparc / mm / fault.c
index 44db335..cc857f6 100644 (file)
@@ -201,6 +201,25 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
        return 0;
 }
 
+extern unsigned long safe_compute_effective_address(struct pt_regs *,
+                                                   unsigned int);
+
+static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
+{
+       unsigned int insn;
+
+       if (text_fault)
+               return regs->pc;
+
+       if (regs->psr & PSR_PS) {
+               insn = *(unsigned int *) regs->pc;
+       } else {
+               __get_user(insn, (unsigned int *) regs->pc);
+       }
+
+       return safe_compute_effective_address(regs, insn);
+}
+
 asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
                               unsigned long address)
 {
@@ -307,7 +326,7 @@ bad_area_nosemaphore:
                info.si_errno = 0;
                /* info.si_code set above to make clear whether
                   this was a SEGV_MAPERR or SEGV_ACCERR fault.  */
-               info.si_addr = (void *)address;
+               info.si_addr = (void *) compute_si_addr(regs, text_fault);
                info.si_trapno = 0;
                force_sig_info (SIGSEGV, &info, tsk);
                return;
@@ -361,7 +380,7 @@ do_sigbus:
        info.si_signo = SIGBUS;
        info.si_errno = 0;
        info.si_code = BUS_ADRERR;
-       info.si_addr = (void *)address;
+       info.si_addr = (void *) compute_si_addr(regs, text_fault);
        info.si_trapno = 0;
        force_sig_info (SIGBUS, &info, tsk);
        if (!from_user)
@@ -530,7 +549,7 @@ bad_area:
        info.si_errno = 0;
        /* info.si_code set above to make clear whether
           this was a SEGV_MAPERR or SEGV_ACCERR fault.  */
-       info.si_addr = (void *)address;
+       info.si_addr = (void *) address;
        info.si_trapno = 0;
        force_sig_info (SIGSEGV, &info, tsk);
        return;
@@ -540,7 +559,7 @@ do_sigbus:
        info.si_signo = SIGBUS;
        info.si_errno = 0;
        info.si_code = BUS_ADRERR;
-       info.si_addr = (void *)address;
+       info.si_addr = (void *) address;
        info.si_trapno = 0;
        force_sig_info (SIGBUS, &info, tsk);
 }