]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - arch/s390/mm/fault.c
9p: move readn meta-function from client to fs layer
[linux-2.6.git] / arch / s390 / mm / fault.c
index 2456b52ed0687e4ac588fa47ae860cc0973636fa..4d537205e83c0013d159a9cd8fc5145e0dd80813 100644 (file)
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
 #include <linux/uaccess.h>
-
+#include <linux/hugetlb.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/s390_ext.h>
+#include <asm/mmu_context.h>
+#include "../kernel/entry.h"
 
 #ifndef CONFIG_64BIT
 #define __FAIL_ADDR_MASK 0x7ffff000
@@ -49,8 +51,6 @@
 extern int sysctl_userprocess_debug;
 #endif
 
-extern void die(const char *,struct pt_regs *,long);
-
 #ifdef CONFIG_KPROBES
 static inline int notify_page_fault(struct pt_regs *regs, long err)
 {
@@ -244,11 +244,6 @@ static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
 }
 
 #ifdef CONFIG_S390_EXEC_PROTECT
-extern long sys_sigreturn(struct pt_regs *regs);
-extern long sys_rt_sigreturn(struct pt_regs *regs);
-extern long sys32_sigreturn(struct pt_regs *regs);
-extern long sys32_rt_sigreturn(struct pt_regs *regs);
-
 static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
                         unsigned long address, unsigned long error_code)
 {
@@ -269,15 +264,15 @@ static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
 #ifdef CONFIG_COMPAT
        compat = test_tsk_thread_flag(current, TIF_31BIT);
        if (compat && instruction == 0x0a77)
-               sys32_sigreturn(regs);
+               sys32_sigreturn();
        else if (compat && instruction == 0x0aad)
-               sys32_rt_sigreturn(regs);
+               sys32_rt_sigreturn();
        else
 #endif
        if (instruction == 0x0a77)
-               sys_sigreturn(regs);
+               sys_sigreturn();
        else if (instruction == 0x0aad)
-               sys_rt_sigreturn(regs);
+               sys_rt_sigreturn();
        else {
                current->thread.prot_addr = address;
                current->thread.trap_no = error_code;
@@ -373,6 +368,8 @@ good_area:
        }
 
 survive:
+       if (is_vm_hugetlb_page(vma))
+               address &= HPAGE_MASK;
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -423,7 +420,7 @@ no_context:
 }
 
 void __kprobes do_protection_exception(struct pt_regs *regs,
-                                      unsigned long error_code)
+                                      long error_code)
 {
        /* Protection exception is supressing, decrement psw address. */
        regs->psw.addr -= (error_code >> 16);
@@ -439,11 +436,50 @@ void __kprobes do_protection_exception(struct pt_regs *regs,
        do_exception(regs, 4, 1);
 }
 
-void __kprobes do_dat_exception(struct pt_regs *regs, unsigned long error_code)
+void __kprobes do_dat_exception(struct pt_regs *regs, long error_code)
 {
        do_exception(regs, error_code & 0xff, 0);
 }
 
+#ifdef CONFIG_64BIT
+void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code)
+{
+       struct mm_struct *mm;
+       struct vm_area_struct *vma;
+       unsigned long address;
+       int space;
+
+       mm = current->mm;
+       address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
+       space = check_space(current);
+
+       if (unlikely(space == 0 || in_atomic() || !mm))
+               goto no_context;
+
+       local_irq_enable();
+
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, address);
+       up_read(&mm->mmap_sem);
+
+       if (vma) {
+               update_mm(mm, current);
+               return;
+       }
+
+       /* User mode accesses just cause a SIGSEGV */
+       if (regs->psw.mask & PSW_MASK_PSTATE) {
+               current->thread.prot_addr = address;
+               current->thread.trap_no = error_code;
+               do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+               return;
+       }
+
+no_context:
+       do_no_context(regs, error_code, address);
+}
+#endif
+
 #ifdef CONFIG_PFAULT 
 /*
  * 'pfault' pseudo page faults routines.