Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / sparc / mm / fault.c
index ea2a40a..9eeed33 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/module.h>
 
 #include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/memreg.h>
@@ -34,8 +33,6 @@
 #include <asm/kdebug.h>
 #include <asm/uaccess.h>
 
-#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
-
 extern int prom_node_root;
 
 /* At boot time we determine these two values necessary for setting
@@ -201,6 +198,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)
 {
@@ -275,16 +291,17 @@ good_area:
         * the fault.
         */
        switch (handle_mm_fault(mm, vma, address, write)) {
-       case 1:
-               current->min_flt++;
-               break;
-       case 2:
+       case VM_FAULT_SIGBUS:
+               goto do_sigbus;
+       case VM_FAULT_OOM:
+               goto out_of_memory;
+       case VM_FAULT_MAJOR:
                current->maj_flt++;
                break;
-       case 0:
-               goto do_sigbus;
+       case VM_FAULT_MINOR:
        default:
-               goto out_of_memory;
+               current->min_flt++;
+               break;
        }
        up_read(&mm->mmap_sem);
        return;
@@ -307,7 +324,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 __user *)compute_si_addr(regs, text_fault);
                info.si_trapno = 0;
                force_sig_info (SIGSEGV, &info, tsk);
                return;
@@ -361,7 +378,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 __user *) compute_si_addr(regs, text_fault);
        info.si_trapno = 0;
        force_sig_info (SIGBUS, &info, tsk);
        if (!from_user)
@@ -412,10 +429,10 @@ asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
                address = regs->pc;
        } else if (!write &&
                   !(regs->psr & PSR_PS)) {
-               unsigned int insn, *ip;
+               unsigned int insn, __user *ip;
 
-               ip = (unsigned int *)regs->pc;
-               if (! get_user(insn, ip)) {
+               ip = (unsigned int __user *)regs->pc;
+               if (!get_user(insn, ip)) {
                        if ((insn & 0xc1680000) == 0xc0680000)
                                write = 1;
                }
@@ -516,8 +533,11 @@ good_area:
                if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
-       if (!handle_mm_fault(mm, vma, address, write))
+       switch (handle_mm_fault(mm, vma, address, write)) {
+       case VM_FAULT_SIGBUS:
+       case VM_FAULT_OOM:
                goto do_sigbus;
+       }
        up_read(&mm->mmap_sem);
        return;
 bad_area:
@@ -530,7 +550,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 __user *) address;
        info.si_trapno = 0;
        force_sig_info (SIGSEGV, &info, tsk);
        return;
@@ -540,7 +560,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 __user *) address;
        info.si_trapno = 0;
        force_sig_info (SIGBUS, &info, tsk);
 }