Merge branch 'i2c-fixes' of git://aeryn.fluff.org.uk/bjdooks/linux
[safe/jmp/linux-2.6] / arch / powerpc / mm / fault.c
index 77953f4..565b7a2 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/kprobes.h>
+#include <linux/kdebug.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
-#include <asm/kdebug.h>
 #include <asm/siginfo.h>
 
-#ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
-
-/* Hook to register for page fault notifications */
-int register_page_fault_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
-}
 
-int unregister_page_fault_notifier(struct notifier_block *nb)
+#ifdef CONFIG_KPROBES
+static inline int notify_page_fault(struct pt_regs *regs)
 {
-       return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
-}
+       int ret = 0;
+
+       /* kprobe_running() needs smp_processor_id() */
+       if (!user_mode(regs)) {
+               preempt_disable();
+               if (kprobe_running() && kprobe_fault_handler(regs, 11))
+                       ret = 1;
+               preempt_enable();
+       }
 
-static inline int notify_page_fault(enum die_val val, const char *str,
-                       struct pt_regs *regs, long err, int trap, int sig)
-{
-       struct die_args args = {
-               .regs = regs,
-               .str = str,
-               .err = err,
-               .trapnr = trap,
-               .signr = sig
-       };
-       return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+       return ret;
 }
 #else
-static inline int notify_page_fault(enum die_val val, const char *str,
-                       struct pt_regs *regs, long err, int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs)
 {
-       return NOTIFY_DONE;
+       return 0;
 }
 #endif
 
@@ -111,31 +100,6 @@ static int store_updates_sp(struct pt_regs *regs)
        return 0;
 }
 
-#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
-static void do_dabr(struct pt_regs *regs, unsigned long address,
-                   unsigned long error_code)
-{
-       siginfo_t info;
-
-       if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
-                       11, SIGSEGV) == NOTIFY_STOP)
-               return;
-
-       if (debugger_dabr_match(regs))
-               return;
-
-       /* Clear the DABR */
-       set_dabr(0);
-
-       /* Deliver the signal to userspace */
-       info.si_signo = SIGTRAP;
-       info.si_errno = 0;
-       info.si_code = TRAP_HWBKPT;
-       info.si_addr = (void __user *)address;
-       force_sig_info(SIGTRAP, &info, current);
-}
-#endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/
-
 /*
  * For 600- and 800-family processors, the error_code parameter is DSISR
  * for a data fault, SRR1 for an instruction fault. For 400-family processors
@@ -156,7 +120,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
        struct mm_struct *mm = current->mm;
        siginfo_t info;
        int code = SEGV_MAPERR;
-       int is_write = 0;
+       int is_write = 0, ret;
        int trap = TRAP(regs);
        int is_exec = trap == 0x400;
 
@@ -175,14 +139,11 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
        is_write = error_code & ESR_DST;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
 
-       if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs, error_code,
-                               11, SIGSEGV) == NOTIFY_STOP)
+       if (notify_page_fault(regs))
                return 0;
 
-       if (trap == 0x300) {
-               if (debugger_fault_handler(regs))
-                       return 0;
-       }
+       if (unlikely(debugger_fault_handler(regs)))
+               return 0;
 
        /* On a kernel SLB miss we can only check for a valid exception entry */
        if (!user_mode(regs) && (address >= TASK_SIZE))
@@ -201,7 +162,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
                        return SIGSEGV;
                /* in_atomic() in user mode is really bad,
                   as is current->mm == NULL. */
-               printk(KERN_EMERG "Page fault in user mode with"
+               printk(KERN_EMERG "Page fault in user mode with "
                       "in_atomic() = %d mm = %p\n", in_atomic(), mm);
                printk(KERN_EMERG "NIP = %lx  MSR = %lx\n",
                       regs->nip, regs->msr);
@@ -291,14 +252,19 @@ good_area:
 #endif /* CONFIG_8xx */
 
        if (is_exec) {
-#ifdef CONFIG_PPC64
+#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
                /* protection fault */
                if (error_code & DSISR_PROTFAULT)
                        goto bad_area;
-               if (!(vma->vm_flags & VM_EXEC))
+               /*
+                * Allow execution from readable areas if the MMU does not
+                * provide separate controls over reading and executing.
+                */
+               if (!(vma->vm_flags & VM_EXEC) &&
+                   (cpu_has_feature(CPU_FTR_NOEXECUTE) ||
+                    !(vma->vm_flags & (VM_READ | VM_WRITE))))
                        goto bad_area;
-#endif
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#else
                pte_t *ptep;
                pmd_t *pmdp;
 
@@ -315,8 +281,9 @@ good_area:
                                        flush_dcache_icache_page(page);
                                        set_bit(PG_arch_1, &page->flags);
                                }
-                               pte_update(ptep, 0, _PAGE_HWEXEC);
-                               _tlbie(address);
+                               pte_update(ptep, 0, _PAGE_HWEXEC |
+                                          _PAGE_ACCESSED);
+                               _tlbie(address, mm->context.id);
                                pte_unmap_unlock(ptep, ptl);
                                up_read(&mm->mmap_sem);
                                return 0;
@@ -343,22 +310,18 @@ good_area:
         * the fault.
         */
  survive:
-       switch (handle_mm_fault(mm, vma, address, is_write)) {
-
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       case VM_FAULT_SIGBUS:
-               goto do_sigbus;
-       case VM_FAULT_OOM:
-               goto out_of_memory;
-       default:
+       ret = handle_mm_fault(mm, vma, address, is_write);
+       if (unlikely(ret & VM_FAULT_ERROR)) {
+               if (ret & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (ret & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
                BUG();
        }
-
+       if (ret & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
        up_read(&mm->mmap_sem);
        return 0;
 
@@ -386,14 +349,14 @@ bad_area_nosemaphore:
  */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       if (current->pid == 1) {
+       if (is_global_init(current)) {
                yield();
                down_read(&mm->mmap_sem);
                goto survive;
        }
        printk("VM: killing process %s\n", current->comm);
        if (user_mode(regs))
-               do_exit(SIGKILL);
+               do_group_exit(SIGKILL);
        return SIGKILL;
 
 do_sigbus:
@@ -426,18 +389,21 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
 
        /* kernel has accessed a bad area */
 
-       printk(KERN_ALERT "Unable to handle kernel paging request for ");
        switch (regs->trap) {
-               case 0x300:
-               case 0x380:
-                       printk("data at address 0x%08lx\n", regs->dar);
-                       break;
-               case 0x400:
-               case 0x480:
-                       printk("instruction fetch\n");
-                       break;
-               default:
-                       printk("unknown fault\n");
+       case 0x300:
+       case 0x380:
+               printk(KERN_ALERT "Unable to handle kernel paging request for "
+                       "data at address 0x%08lx\n", regs->dar);
+               break;
+       case 0x400:
+       case 0x480:
+               printk(KERN_ALERT "Unable to handle kernel paging request for "
+                       "instruction fetch\n");
+               break;
+       default:
+               printk(KERN_ALERT "Unable to handle kernel paging request for "
+                       "unknown fault\n");
+               break;
        }
        printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n",
                regs->nip);