Merge branch 'siginfo-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebieder...
[linux-2.6-microblaze.git] / arch / x86 / mm / fault.c
index 2b1519b..b24eb4e 100644 (file)
@@ -157,79 +157,6 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
        return prefetch;
 }
 
-/*
- * A protection key fault means that the PKRU value did not allow
- * access to some PTE.  Userspace can figure out what PKRU was
- * from the XSAVE state, and this function fills out a field in
- * siginfo so userspace can discover which protection key was set
- * on the PTE.
- *
- * If we get here, we know that the hardware signaled a X86_PF_PK
- * fault and that there was a VMA once we got in the fault
- * handler.  It does *not* guarantee that the VMA we find here
- * was the one that we faulted on.
- *
- * 1. T1   : mprotect_key(foo, PAGE_SIZE, pkey=4);
- * 2. T1   : set PKRU to deny access to pkey=4, touches page
- * 3. T1   : faults...
- * 4.    T2: mprotect_key(foo, PAGE_SIZE, pkey=5);
- * 5. T1   : enters fault handler, takes mmap_sem, etc...
- * 6. T1   : reaches here, sees vma_pkey(vma)=5, when we really
- *          faulted on a pte with its pkey=4.
- */
-static void fill_sig_info_pkey(int si_signo, int si_code, siginfo_t *info,
-               u32 *pkey)
-{
-       /* This is effectively an #ifdef */
-       if (!boot_cpu_has(X86_FEATURE_OSPKE))
-               return;
-
-       /* Fault not from Protection Keys: nothing to do */
-       if ((si_code != SEGV_PKUERR) || (si_signo != SIGSEGV))
-               return;
-       /*
-        * force_sig_info_fault() is called from a number of
-        * contexts, some of which have a VMA and some of which
-        * do not.  The X86_PF_PK handing happens after we have a
-        * valid VMA, so we should never reach this without a
-        * valid VMA.
-        */
-       if (!pkey) {
-               WARN_ONCE(1, "PKU fault with no VMA passed in");
-               info->si_pkey = 0;
-               return;
-       }
-       /*
-        * si_pkey should be thought of as a strong hint, but not
-        * absolutely guranteed to be 100% accurate because of
-        * the race explained above.
-        */
-       info->si_pkey = *pkey;
-}
-
-static void
-force_sig_info_fault(int si_signo, int si_code, unsigned long address,
-                    struct task_struct *tsk, u32 *pkey, int fault)
-{
-       unsigned lsb = 0;
-       siginfo_t info;
-
-       clear_siginfo(&info);
-       info.si_signo   = si_signo;
-       info.si_errno   = 0;
-       info.si_code    = si_code;
-       info.si_addr    = (void __user *)address;
-       if (fault & VM_FAULT_HWPOISON_LARGE)
-               lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); 
-       if (fault & VM_FAULT_HWPOISON)
-               lsb = PAGE_SHIFT;
-       info.si_addr_lsb = lsb;
-
-       fill_sig_info_pkey(si_signo, si_code, &info, pkey);
-
-       force_sig_info(si_signo, &info, tsk);
-}
-
 DEFINE_SPINLOCK(pgd_lock);
 LIST_HEAD(pgd_list);
 
@@ -734,8 +661,8 @@ no_context(struct pt_regs *regs, unsigned long error_code,
                        tsk->thread.cr2 = address;
 
                        /* XXX: hwpoison faults will set the wrong code. */
-                       force_sig_info_fault(signal, si_code, address,
-                                            tsk, NULL, 0);
+                       force_sig_fault(signal, si_code, (void __user *)address,
+                                       tsk);
                }
 
                /*
@@ -862,7 +789,7 @@ static bool is_vsyscall_vaddr(unsigned long vaddr)
 
 static void
 __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
-                      unsigned long address, u32 *pkey, int si_code)
+                      unsigned long address, u32 pkey, int si_code)
 {
        struct task_struct *tsk = current;
 
@@ -898,7 +825,10 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
                tsk->thread.error_code  = error_code;
                tsk->thread.trap_nr     = X86_TRAP_PF;
 
-               force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey, 0);
+               if (si_code == SEGV_PKUERR)
+                       force_sig_pkuerr((void __user *)address, pkey);
+
+               force_sig_fault(SIGSEGV, si_code, (void __user *)address, tsk);
 
                return;
        }
@@ -911,35 +841,29 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
 
 static noinline void
 bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
-                    unsigned long address, u32 *pkey)
+                    unsigned long address)
 {
-       __bad_area_nosemaphore(regs, error_code, address, pkey, SEGV_MAPERR);
+       __bad_area_nosemaphore(regs, error_code, address, 0, SEGV_MAPERR);
 }
 
 static void
 __bad_area(struct pt_regs *regs, unsigned long error_code,
-          unsigned long address,  struct vm_area_struct *vma, int si_code)
+          unsigned long address, u32 pkey, int si_code)
 {
        struct mm_struct *mm = current->mm;
-       u32 pkey;
-
-       if (vma)
-               pkey = vma_pkey(vma);
-
        /*
         * Something tried to access memory that isn't in our memory map..
         * Fix it, but check if it's kernel or user first..
         */
        up_read(&mm->mmap_sem);
 
-       __bad_area_nosemaphore(regs, error_code, address,
-                              (vma) ? &pkey : NULL, si_code);
+       __bad_area_nosemaphore(regs, error_code, address, pkey, si_code);
 }
 
 static noinline void
 bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address)
 {
-       __bad_area(regs, error_code, address, NULL, SEGV_MAPERR);
+       __bad_area(regs, error_code, address, 0, SEGV_MAPERR);
 }
 
 static inline bool bad_area_access_from_pkeys(unsigned long error_code,
@@ -968,18 +892,40 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
         * But, doing it this way allows compiler optimizations
         * if pkeys are compiled out.
         */
-       if (bad_area_access_from_pkeys(error_code, vma))
-               __bad_area(regs, error_code, address, vma, SEGV_PKUERR);
-       else
-               __bad_area(regs, error_code, address, vma, SEGV_ACCERR);
+       if (bad_area_access_from_pkeys(error_code, vma)) {
+               /*
+                * A protection key fault means that the PKRU value did not allow
+                * access to some PTE.  Userspace can figure out what PKRU was
+                * from the XSAVE state.  This function captures the pkey from
+                * the vma and passes it to userspace so userspace can discover
+                * which protection key was set on the PTE.
+                *
+                * If we get here, we know that the hardware signaled a X86_PF_PK
+                * fault and that there was a VMA once we got in the fault
+                * handler.  It does *not* guarantee that the VMA we find here
+                * was the one that we faulted on.
+                *
+                * 1. T1   : mprotect_key(foo, PAGE_SIZE, pkey=4);
+                * 2. T1   : set PKRU to deny access to pkey=4, touches page
+                * 3. T1   : faults...
+                * 4.    T2: mprotect_key(foo, PAGE_SIZE, pkey=5);
+                * 5. T1   : enters fault handler, takes mmap_sem, etc...
+                * 6. T1   : reaches here, sees vma_pkey(vma)=5, when we really
+                *           faulted on a pte with its pkey=4.
+                */
+               u32 pkey = vma_pkey(vma);
+
+               __bad_area(regs, error_code, address, pkey, SEGV_PKUERR);
+       } else {
+               __bad_area(regs, error_code, address, 0, SEGV_ACCERR);
+       }
 }
 
 static void
 do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
-         u32 *pkey, unsigned int fault)
+         unsigned int fault)
 {
        struct task_struct *tsk = current;
-       int code = BUS_ADRERR;
 
        /* Kernel mode? Handle exceptions or die: */
        if (!(error_code & X86_PF_USER)) {
@@ -997,18 +943,25 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
 
 #ifdef CONFIG_MEMORY_FAILURE
        if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
-               printk(KERN_ERR
+               unsigned lsb = 0;
+
+               pr_err(
        "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",
                        tsk->comm, tsk->pid, address);
-               code = BUS_MCEERR_AR;
+               if (fault & VM_FAULT_HWPOISON_LARGE)
+                       lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
+               if (fault & VM_FAULT_HWPOISON)
+                       lsb = PAGE_SHIFT;
+               force_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, tsk);
+               return;
        }
 #endif
-       force_sig_info_fault(SIGBUS, code, address, tsk, pkey, fault);
+       force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, tsk);
 }
 
 static noinline void
 mm_fault_error(struct pt_regs *regs, unsigned long error_code,
-              unsigned long address, u32 *pkey, vm_fault_t fault)
+              unsigned long address, vm_fault_t fault)
 {
        if (fatal_signal_pending(current) && !(error_code & X86_PF_USER)) {
                no_context(regs, error_code, address, 0, 0);
@@ -1032,9 +985,9 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
        } else {
                if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
                             VM_FAULT_HWPOISON_LARGE))
-                       do_sigbus(regs, error_code, address, pkey, fault);
+                       do_sigbus(regs, error_code, address, fault);
                else if (fault & VM_FAULT_SIGSEGV)
-                       bad_area_nosemaphore(regs, error_code, address, pkey);
+                       bad_area_nosemaphore(regs, error_code, address);
                else
                        BUG();
        }
@@ -1267,7 +1220,7 @@ do_kern_addr_fault(struct pt_regs *regs, unsigned long hw_error_code,
         * Don't take the mm semaphore here. If we fixup a prefetch
         * fault we could otherwise deadlock:
         */
-       bad_area_nosemaphore(regs, hw_error_code, address, NULL);
+       bad_area_nosemaphore(regs, hw_error_code, address);
 }
 NOKPROBE_SYMBOL(do_kern_addr_fault);
 
@@ -1283,7 +1236,6 @@ void do_user_addr_fault(struct pt_regs *regs,
        struct mm_struct *mm;
        vm_fault_t fault, major = 0;
        unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
-       u32 pkey;
 
        tsk = current;
        mm = tsk->mm;
@@ -1304,7 +1256,7 @@ void do_user_addr_fault(struct pt_regs *regs,
         * pages in the user address space.
         */
        if (unlikely(smap_violation(hw_error_code, regs))) {
-               bad_area_nosemaphore(regs, hw_error_code, address, NULL);
+               bad_area_nosemaphore(regs, hw_error_code, address);
                return;
        }
 
@@ -1313,7 +1265,7 @@ void do_user_addr_fault(struct pt_regs *regs,
         * in a region with pagefaults disabled then we must not take the fault
         */
        if (unlikely(faulthandler_disabled() || !mm)) {
-               bad_area_nosemaphore(regs, hw_error_code, address, NULL);
+               bad_area_nosemaphore(regs, hw_error_code, address);
                return;
        }
 
@@ -1403,7 +1355,7 @@ void do_user_addr_fault(struct pt_regs *regs,
                         * Fault from code in kernel from
                         * which we do not expect faults.
                         */
-                       bad_area_nosemaphore(regs, sw_error_code, address, NULL);
+                       bad_area_nosemaphore(regs, sw_error_code, address);
                        return;
                }
 retry:
@@ -1467,10 +1419,7 @@ good_area:
         * (potentially after handling any pending signal during the return to
         * userland). The return to userland is identified whenever
         * FAULT_FLAG_USER|FAULT_FLAG_KILLABLE are both set in flags.
-        * Thus we have to be careful about not touching vma after handling the
-        * fault, so we read the pkey beforehand.
         */
-       pkey = vma_pkey(vma);
        fault = handle_mm_fault(vma, address, flags);
        major |= fault & VM_FAULT_MAJOR;
 
@@ -1499,7 +1448,7 @@ good_area:
 
        up_read(&mm->mmap_sem);
        if (unlikely(fault & VM_FAULT_ERROR)) {
-               mm_fault_error(regs, sw_error_code, address, &pkey, fault);
+               mm_fault_error(regs, sw_error_code, address, fault);
                return;
        }