vserver 1.9.3
[linux-2.6.git] / arch / s390 / mm / fault.c
index 9cf3b39..d6bd3d4 100644 (file)
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/module.h>
+#include <linux/hardirq.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/hardirq.h>
 
 #ifndef CONFIG_ARCH_S390X
 #define __FAIL_ADDR_MASK 0x7ffff000
@@ -126,8 +126,8 @@ static inline int check_user_space(struct pt_regs *regs, int error_code)
  * Send SIGSEGV to task.  This is an external routine
  * to keep the stack usage of do_page_fault small.
  */
-static void force_sigsegv(struct pt_regs *regs, unsigned long error_code,
-                         int si_code, unsigned long address)
+static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
+                      int si_code, unsigned long address)
 {
        struct siginfo si;
 
@@ -159,7 +159,8 @@ static void force_sigsegv(struct pt_regs *regs, unsigned long error_code,
  *   11       Page translation     ->  Not present       (nullification)
  *   3b       Region third trans.  ->  Not present       (nullification)
  */
-extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
+extern inline void
+do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
 {
         struct task_struct *tsk;
         struct mm_struct *mm;
@@ -177,7 +178,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
         * as a special case because the translation exception code 
         * field is not guaranteed to contain valid data in this case.
         */
-       if (error_code == 4 && !(S390_lowcore.trans_exc_code & 4)) {
+       if (is_protection && !(S390_lowcore.trans_exc_code & 4)) {
 
                /* Low-address protection hit in kernel mode means 
                   NULL pointer write access in kernel mode.  */
@@ -232,7 +233,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
  */
 good_area:
        si_code = SEGV_ACCERR;
-       if (error_code != 4) {
+       if (!is_protection) {
                /* page not present, check vm flags */
                if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
                        goto bad_area;
@@ -247,7 +248,7 @@ survive:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       switch (handle_mm_fault(mm, vma, address, error_code == 4)) {
+       switch (handle_mm_fault(mm, vma, address, is_protection)) {
        case VM_FAULT_MINOR:
                tsk->min_flt++;
                break;
@@ -263,6 +264,11 @@ survive:
        }
 
         up_read(&mm->mmap_sem);
+       /*
+        * The instruction that caused the program check will
+        * be repeated. Don't signal single step via SIGTRAP.
+        */
+       clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
         return;
 
 /*
@@ -276,7 +282,7 @@ bad_area:
         if (regs->psw.mask & PSW_MASK_PSTATE) {
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
-               force_sigsegv(regs, error_code, si_code, address);
+               do_sigsegv(regs, error_code, si_code, address);
                 return;
        }
 
@@ -337,28 +343,15 @@ do_sigbus:
 void do_protection_exception(struct pt_regs *regs, unsigned long error_code)
 {
        regs->psw.addr -= (error_code >> 16);
-       do_exception(regs, 4);
+       do_exception(regs, 4, 1);
 }
 
-void do_segment_exception(struct pt_regs *regs, unsigned long error_code)
+void do_dat_exception(struct pt_regs *regs, unsigned long error_code)
 {
-       do_exception(regs, 0x10);
+       do_exception(regs, error_code & 0xff, 0);
 }
 
-void do_page_exception(struct pt_regs *regs, unsigned long error_code)
-{
-       do_exception(regs, 0x11);
-}
-
-#ifdef CONFIG_ARCH_S390X
-
-void
-do_region_exception(struct pt_regs *regs, unsigned long error_code)
-{
-       do_exception(regs, 0x3b);
-}
-
-#else /* CONFIG_ARCH_S390X */
+#ifndef CONFIG_ARCH_S390X
 
 typedef struct _pseudo_wait_t {
        struct _pseudo_wait_t *next;
@@ -456,6 +449,11 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
                 wait_struct.next = pseudo_lock_queue;
                 pseudo_lock_queue = &wait_struct;
                 spin_unlock(&pseudo_wait_spinlock);
+               /*
+                * The instruction that caused the program check will
+                * be repeated. Don't signal single step via SIGTRAP.
+                */
+               clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
                 /* go to sleep */
                 wait_event(wait_struct.queue, wait_struct.resolved);
         }