2.5.39 s390 (19/26): ptrace cleanup.

2.5.39 s390 (19/26): ptrace cleanup.

Post by Martin Schwidefsk » Tue, 01 Oct 2002 16:10:09



Rewrite s390 ptrace code in a more readable and less buggy way. As a part of
this, all psw related definitions are moved into ptrace.h from a number of
different locations.

diff -urN linux-2.5.39/arch/s390/kernel/process.c linux-2.5.39-s390/arch/s390/kernel/process.c
--- linux-2.5.39/arch/s390/kernel/process.c     Mon Sep 30 13:33:16 2002
+++ linux-2.5.39-s390/arch/s390/kernel/process.c        Mon Sep 30 13:33:16 2002
@@ -75,9 +75,10 @@

        /*
         * Wait for external, I/O or machine check interrupt and
-        * switch of machine check bit after the wait has ended.
+        * switch off machine check bit after the wait has ended.
         */
-       wait_psw.mask = _WAIT_PSW_MASK;
+       wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
+               PSW_MASK_IO | PSW_MASK_EXT;
        asm volatile (
                "    basr %0,0\n"
                "0:  la   %0,1f-0b(%0)\n"
@@ -114,7 +115,7 @@

        show_registers(regs);
        /* Show stack backtrace if pt_regs is from kernel mode */
-       if (!(regs->psw.mask & PSW_PROBLEM_STATE))
+       if (!(regs->psw.mask & PSW_MASK_PSTATE))
                show_trace((unsigned long *) regs->gprs[15]);
 }

@@ -135,8 +136,8 @@
        struct pt_regs regs;

        memset(&regs, 0, sizeof(regs));
-       regs.psw.mask = _SVC_PSW_MASK;
-       regs.psw.addr = (__u32) kernel_thread_starter | _ADDR_31;
+       regs.psw.mask = PSW_KERNEL_BITS;
+       regs.psw.addr = (__u32) kernel_thread_starter | PSW_ADDR_AMODE31;
        regs.gprs[7] = STACK_FRAME_OVERHEAD;
        regs.gprs[8] = __LC_KERNEL_STACK;
        regs.gprs[9] = (unsigned long) fn;
diff -urN linux-2.5.39/arch/s390/kernel/ptrace.c linux-2.5.39-s390/arch/s390/kernel/ptrace.c
--- linux-2.5.39/arch/s390/kernel/ptrace.c      Fri Sep 27 23:50:32 2002
+++ linux-2.5.39-s390/arch/s390/kernel/ptrace.c Mon Sep 30 13:33:16 2002
@@ -4,6 +4,7 @@
  *  S390 version
  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Denis Joseph Barrow (djbar...@de.ibm.com,barrow...@yahoo.com),
+ *               Martin Schwidefsky (schwidef...@de.ibm.com)
  *
  *  Based on PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (g...@linuxppc.org)
@@ -21,7 +22,6 @@
  * this archive for more details.
  */

-#include <stddef.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -39,266 +39,216 @@
 #include <asm/uaccess.h>

-void FixPerRegisters(struct task_struct *task)
+static void FixPerRegisters(struct task_struct *task)
 {
-       struct pt_regs *regs = __KSTK_PTREGS(task);
-       per_struct *per_info=
-                       (per_struct *)&task->thread.per_info;
+       struct pt_regs *regs;
+       per_struct *per_info;

-       per_info->control_regs.bits.em_instruction_fetch=
-       per_info->single_step|per_info->instruction_fetch;
+       regs = __KSTK_PTREGS(task);
+       per_info = (per_struct *) &task->thread.per_info;
+       per_info->control_regs.bits.em_instruction_fetch =
+               per_info->single_step | per_info->instruction_fetch;

-       if(per_info->single_step)
-       {
-               per_info->control_regs.bits.starting_addr=0;
-               per_info->control_regs.bits.ending_addr=0x7fffffffUL;
-       }
-       else
-       {
-               per_info->control_regs.bits.starting_addr=
-               per_info->starting_addr;
-               per_info->control_regs.bits.ending_addr=
-               per_info->ending_addr;
-       }
-       /* if any of the control reg tracing bits are on
-          we switch on per in the psw */
-       if(per_info->control_regs.words.cr[0]&PER_EM_MASK)
-               regs->psw.mask |=PSW_PER_MASK;
+       if (per_info->single_step) {
+               per_info->control_regs.bits.starting_addr = 0;
+               per_info->control_regs.bits.ending_addr = 0x7fffffffUL;
+       } else {
+               per_info->control_regs.bits.starting_addr =
+                       per_info->starting_addr;
+               per_info->control_regs.bits.ending_addr =
+                       per_info->ending_addr;
+       }
+       /*
+        * if any of the control reg tracing bits are on
+        * we switch on per in the psw
+        */
+       if (per_info->control_regs.words.cr[0] & PER_EM_MASK)
+               regs->psw.mask |= PSW_MASK_PER;
        else
-               regs->psw.mask &= ~PSW_PER_MASK;
+               regs->psw.mask &= ~PSW_MASK_PER;
+
        if (per_info->control_regs.bits.em_storage_alteration)
-       {
-               per_info->control_regs.bits.storage_alt_space_ctl=1;
-               //((pgd_t *)__pa(task->mm->pgd))->pgd |= USER_STD_MASK;
-       }
+               per_info->control_regs.bits.storage_alt_space_ctl = 1;
        else
-       {
-               per_info->control_regs.bits.storage_alt_space_ctl=0;
-               //((pgd_t *)__pa(task->mm->pgd))->pgd &= ~USER_STD_MASK;
-       }
+               per_info->control_regs.bits.storage_alt_space_ctl = 0;
 }

 void set_single_step(struct task_struct *task)
 {
-       per_struct *per_info=
-                       (per_struct *)&task->thread.per_info;    
-      
-       per_info->single_step=1;  /* Single step */
+       task->thread.per_info.single_step = 1;
        FixPerRegisters(task);
 }

 void clear_single_step(struct task_struct *task)
 {
-       per_struct *per_info=
-                       (per_struct *)&task->thread.per_info;
-
-       per_info->single_step=0;
+       task->thread.per_info.single_step = 0;
        FixPerRegisters(task);
 }

-int ptrace_usercopy(addr_t realuseraddr,addr_t copyaddr,int len,int tofromuser,int writeuser,u32 mask)
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
 {
-       u32  tempuser;
-       int  retval=0;
-      
-       if(writeuser&&realuseraddr==(addr_t)NULL)
-               return(0);
-       if(mask!=0xffffffff)
-       {
-               tempuser=*((u32 *)realuseraddr);
-               if(!writeuser)
-               {
-                       tempuser&=mask;
-                       realuseraddr=(addr_t)&tempuser;
-               }
-       }
-       if(tofromuser)
-       {
-               if(writeuser)
-               {
-                       retval=copy_from_user((void *)realuseraddr,(void *)copyaddr,len) ? -EFAULT : 0;
-               }
-               else
-               {
-                       if(realuseraddr==(addr_t)NULL)
-                               retval=(clear_user((void *)copyaddr,len) ? -EIO:0);
-                       else
-                               retval=(copy_to_user((void *)copyaddr,(void *)realuseraddr,len) ? -EIO:0);
-               }      
-       }
-       else
-       {
-               if(writeuser)
-                       memcpy((void *)realuseraddr,(void *)copyaddr,len);
-               else
-                       memcpy((void *)copyaddr,(void *)realuseraddr,len);
-       }
-       if(mask!=0xffffffff&&writeuser)
-                       (*((u32 *)realuseraddr))=(((*((u32 *)realuseraddr))&mask)|(tempuser&~mask));
-       return(retval);
+       /* make sure the single step bit is not set. */
+       clear_single_step(child);
 }

-int copy_user(struct task_struct *task,saddr_t useraddr,addr_t copyaddr,int len,int tofromuser,int writingtouser)
+/*
+ * Read the word at offset addr from the user area of a process. The
+ * trouble here is that the information is littered over different
+ * locations. The process registers are found on the kernel stack,
+ * the floating point stuff and the trace settings are stored in
+ * the task structure. In addition the different structures in
+ * struct user contain pad bytes that should be read as zeroes.
+ * Lovely...
+ */
+static int peek_user(struct task_struct *child, addr_t addr, addr_t data)
 {
-       int copylen=0,copymax;
-       addr_t  realuseraddr;
-       saddr_t enduseraddr=useraddr+len;
-      
-       u32 mask;
+       struct user *dummy = NULL;
+       addr_t offset;
+       __u32 tmp;
+
+       if ((addr & 3) || addr > sizeof(struct user) - 3)
+               return -EIO;
+
+       if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
+               /*
+                * psw, gprs, acrs and orig_gpr2 are stored on the stack
+                */
+               tmp = *(__u32 *)((addr_t) __KSTK_PTREGS(child) + addr);
+
+       } else if (addr >= (addr_t) &dummy->regs.fp_regs &&
+                  addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
+               /*
+                * floating point regs. are stored in the thread structure
+                */
+               offset = addr - (addr_t) &dummy->regs.fp_regs;
+               tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset);
+
+       } else if (addr >= (addr_t) &dummy->regs.per_info &&
+                  addr < (addr_t) (&dummy->regs.per_info + 1)) {
+               /*
+                * per_info is found in the thread structure
+                */
+               offset = addr - (addr_t) &dummy->regs.per_info;
+               tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset);

-       if (useraddr < 0 || enduseraddr > sizeof(struct user)||
-          (useraddr < PT_ENDREGS && (useraddr&3))||
-          (enduseraddr < PT_ENDREGS && (enduseraddr&3)))
-               return (-EIO);
-       while(len>0)
-       {
-               mask=0xffffffff;
-               if(useraddr<PT_FPC)
-               {
-                       realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr;
-                       if(useraddr<PT_PSWMASK)
-                       {
-                               copymax=PT_PSWMASK;
-                       }
-                       else if(useraddr<(PT_PSWMASK+4))
-                       {
-                               copymax=(PT_PSWMASK+4);
-                               if(writingtouser)
-                                       mask=PSW_MASK_DEBUGCHANGE;
-                       }
-                       else if(useraddr<(PT_PSWADDR+4))
-                       {
-                               copymax=PT_PSWADDR+4;
-                               mask=PSW_ADDR_DEBUGCHANGE;
-                       }
-                       else
-                               copymax=PT_FPC;
-                      
-               }
-               else if(useraddr<(PT_FPR15_LO+4))
-               {
-                       copymax=(PT_FPR15_LO+4);
-                       realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]);
-               }
-               else if(useraddr<sizeof(struct user_regs_struct))
-               {
-                       copymax=sizeof(struct user_regs_struct);
-                       realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
-               }
-               else
-               {
-                       copymax=sizeof(struct user);
-                       realuseraddr=(addr_t)NULL;
-               }
-               copylen=copymax-useraddr;
-               copylen=(copylen>len ? len:copylen);
-               if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask))
-                       return (-EIO);
-               copyaddr+=copylen;
-               len-=copylen;
-               useraddr+=copylen;
-       }
-       FixPerRegisters(task);
-       return(0);
+       } else
+               tmp = 0;
+
+       return put_user(tmp, (__u32 *) data);
 }

 /*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure single step bits etc are not set.
+ * Write a word to the user area of a process at location addr. This
+ * operation does have an additional problem compared to peek_user.
+ * Stores to the program status word and on the floating point
+ * control register needs to get checked for validity.
  */
-void ptrace_disable(struct task_struct *child)
+static int poke_user(struct task_struct *child, addr_t addr, addr_t data)
 {
-       /* make sure the single step bit is not set. */
-       clear_single_step(child);
+       struct user *dummy = NULL;
+       addr_t offset;
+
+       if ((addr & 3) || addr > sizeof(struct user) - 3)
+               return -EIO;
+
+       if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
+               /*
+                * psw, gprs, acrs and orig_gpr2 are stored on the stack
+                */
+               if (addr == (addr_t) &dummy->regs.psw.mask &&
+                   (data & ~PSW_MASK_CC) != PSW_USER_BITS)
+                       /* Invalid psw mask. */
+                       return -EINVAL;
+               if (addr == (addr_t) &dummy->regs.psw.addr)
+                       /* I'd like to reject addresses without the
+                          high order bit but older gdb's rely on it */
+                       data |= PSW_ADDR_AMODE31;
+               *(__u32 *)((addr_t) __KSTK_PTREGS(child) + addr) = data;
+
+       } else if (addr >= (addr_t) &dummy->regs.fp_regs &&
+                  addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
+               /*
+                * floating point regs. are stored in the thread structure
+                */
+               if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
+                   (data & ~FPC_VALID_MASK) != 0)
+                       return -EINVAL;
+               offset = addr - (addr_t) &dummy->regs.fp_regs;
+               *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = data;
+
+       } else if (addr >= (addr_t) &dummy->regs.per_info &&
+                  addr < (addr_t) (&dummy->regs.per_info + 1)) {
+               /*
+                * per_info is found in the thread structure
+                */
+               offset = addr - (addr_t) &dummy->regs.per_info;
+               *(__u32 *)((addr_t) &child->thread.per_info + offset) = data;
+
+       }
+
+       FixPerRegisters(child);
+       return 0;
 }

-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+static int
+do_ptrace(struct task_struct *child, long request, long addr, long data)
 {
-       struct task_struct *child;
-       int ret = -EPERM;
        unsigned long tmp;
-       int copied;
-       ptrace_area   parea;
+       ptrace_area parea;
+       int copied, ret;

-       lock_kernel();
-       if (request == PTRACE_TRACEME)
-       {
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED)
-                       goto out;
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
-               ret = 0;
-               goto out;
-       }
-       ret = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (!child)
-               goto out;
-       ret = -EPERM;
-       if (pid == 1)           /* you may not mess with init */
-               goto out_tsk;
-       if (request == PTRACE_ATTACH)
-       {
-               ret = ptrace_attach(child);
-               goto out_tsk;
-       }
-       ret = -ESRCH;
-       // printk("child=%lX child->flags=%lX",child,child->flags);
-       /* I added child!=current line so we can get the */
-       /* ieee_instruction_pointer from the user structure DJB */
-       if(child!=current)
-       {
-               if (!(child->ptrace & PT_PTRACED))
-                       goto out_tsk;
-               if (child->state != TASK_STOPPED)
-               {
-                       if (request != PTRACE_KILL)
-                               goto out_tsk;
-               }
-               if (child->parent != current)
-                       goto out_tsk;
-       }
-       switch (request)
-       {
-               /* If I and D space are separate, these will need to be fixed. */
-       case PTRACE_PEEKTEXT: /* read word at location addr. */
-       case PTRACE_PEEKDATA:
-               copied = access_process_vm(child,ADDR_BITS_REMOVE(addr), &tmp, sizeof(tmp), 0);
-               ret = -EIO;
+       if (request == PTRACE_ATTACH)
+               return ptrace_attach(child);
+
+       /*
+        * I added child != current line so we can get the
+        * ieee_instruction_pointer from the user structure DJB
+        */
+       if (child != current) {
+               ret = ptrace_check_attach(child, request == PTRACE_KILL);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Remove high order bit from address. */
+       addr &= PSW_ADDR_INSN;
+
+       switch (request) {
+       case PTRACE_PEEKTEXT:
+       case PTRACE_PEEKDATA:
+               /* read word at location addr. */
+               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
                if (copied != sizeof(tmp))
-                       break;
-               ret = put_user(tmp,(unsigned long *) data);
-               break;
+                       return -EIO;
+               return put_user(tmp, (unsigned long *) data);

-               /* read the word at location addr in the USER area. */
        case PTRACE_PEEKUSR:
-               ret=copy_user(child,addr,data,sizeof(unsigned long),1,0);
-               break;
+               /* read the word at location addr in the USER area. */
+               return peek_user(child, addr, data);

-               /* If I and D space are separate, this will have to be fixed. */
-       case PTRACE_POKETEXT: /* write the word at location addr. */
+       case PTRACE_POKETEXT:
        case PTRACE_POKEDATA:
-               ret = 0;
-               if (access_process_vm(child,ADDR_BITS_REMOVE(addr), &data, sizeof(data), 1) == sizeof(data))
-                       break;
-               ret = -EIO;
-               break;
-
-       case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-               ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned long),0,1);
-               break;
-
-       case PTRACE_SYSCALL:    /* continue and stop at next (return from) syscall */
-       case PTRACE_CONT:        /* restart after signal. */
-               ret = -EIO;
+               /* write the word at location addr. */
+               copied = access_process_vm(child, addr, &data, sizeof(data),1);
+               if (copied != sizeof(data))
+                       return -EIO;
+               return 0;
+
+       case PTRACE_POKEUSR:
+               /* write the word at location addr in the USER area */
+               return poke_user(child, addr, data);
+
+       case PTRACE_SYSCALL:
+               /* continue and stop at next (return from) syscall */
+       case PTRACE_CONT:
+               /* restart after signal. */
                if ((unsigned long) data >= _NSIG)
-                       break;
+                       return -EIO;
                if (request == PTRACE_SYSCALL)
                        set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
                else
@@ -307,60 +257,104 @@
                /* make sure the single step bit is not set. */
                clear_single_step(child);
                wake_up_process(child);
-               ret = 0;
-               break;
+               return 0;

-/*
- * make the child exit.  Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
        case PTRACE_KILL:
-               ret = 0;
+               /*
+                * make the child exit.  Best I can do is send it a sigkill.
+                * perhaps it should be put in the status that it wants to
+                * exit.
+                */
                if (child->state == TASK_ZOMBIE) /* already dead */
-                       break;
+                       return 0;
                child->exit_code = SIGKILL;
+               /* make sure the single step bit is not set. */
                clear_single_step(child);
                wake_up_process(child);
-               /* make sure the single step bit is not set. */
-               break;
+               return 0;

-       case PTRACE_SINGLESTEP:  /* set the trap flag. */
-               ret = -EIO;
+       case PTRACE_SINGLESTEP:
+               /* set the trap flag. */
                if ((unsigned long) data >= _NSIG)
-                       break;
+                       return -EIO;
                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
                child->exit_code = data;
                set_single_step(child);
                /* give it a chance to run. */
                wake_up_process(child);
-               ret = 0;
-               break;
+               return 0;
+
+       case PTRACE_DETACH:
+               /* detach a process that was attached. */
+               return ptrace_detach(child, data);

-       case PTRACE_DETACH:  /* detach a process that was attached. */
-               ret = ptrace_detach(child, data);
-               break;
        case PTRACE_PEEKUSR_AREA:
        case PTRACE_POKEUSR_AREA:
-               if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
-                  ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-                                parea.len,1,(request==PTRACE_POKEUSR_AREA));
-               break;
-       case PTRACE_SETOPTIONS: {
+               if (!copy_from_user(&parea, (void *) addr, sizeof(parea)))
+                       return -EFAULT;
+               addr = parea.kernel_addr;
+               data = parea.process_addr;
+               copied = 0;
+               while (copied < parea.len) {
+                       if (request == PTRACE_PEEKUSR_AREA)
+                               ret = peek_user(child, addr, data);
+                       else
+                               ret = poke_user(child, addr, data);
+                       if (ret)
+                               return ret;
+                       addr += sizeof(unsigned long);
+                       data += sizeof(unsigned long);
+                       copied += sizeof(unsigned long);
+               }
+               return 0;
+
+       case PTRACE_SETOPTIONS:
                if (data & PTRACE_O_TRACESYSGOOD)
                        child->ptrace |= PT_TRACESYSGOOD;
                else
                        child->ptrace &= ~PT_TRACESYSGOOD;
-               ret = 0;
-               break;
+               return 0;
        }
-       default:
-               ret = -EIO;
-               break;
+       return -EIO;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+       struct task_struct *child;
+       int ret;
+
+       lock_kernel();
+
+       if (request == PTRACE_TRACEME) {
+               /* are we already being traced? */
+               ret = -EPERM;
+               if (current->ptrace & PT_PTRACED)
+                       goto out;
+               ret = security_ops->ptrace(current->parent, current);
+               if (ret)
+                       goto out;
+               /* set the ptrace bit in the process flags. */
+               current->ptrace |= PT_PTRACED;
+               goto out;
        }
- out_tsk:
+
+       ret = -EPERM;
+       if (pid == 1)           /* you may not mess with init */
+               goto out;
+
+       ret = -ESRCH;
+       read_lock(&tasklist_lock);
+       child = find_task_by_pid(pid);
+       if (child)
+               get_task_struct(child);
+       read_unlock(&tasklist_lock);
+       if (!child)
+               goto out;
+
+       ret = do_ptrace(child, request, addr, data);
+
        put_task_struct(child);
- out:
+out:
        unlock_kernel();
        return ret;
 }
@@ -371,8 +365,8 @@
                return;
        if (!(current->ptrace & PT_PTRACED))
                return;
-       current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-                                       ? 0x80 : 0);
+       current->exit_code =
+               SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0);
        current->state = TASK_STOPPED;
        notify_parent(current, SIGCHLD);
        schedule();
diff -urN linux-2.5.39/arch/s390/kernel/setup.c linux-2.5.39-s390/arch/s390/kernel/setup.c
--- linux-2.5.39/arch/s390/kernel/setup.c       Mon Sep 30 13:33:09 2002
+++ linux-2.5.39-s390/arch/s390/kernel/setup.c  Mon Sep 30 13:33:16 2002
@@ -304,7 +304,7 @@
        unsigned long start_pfn, end_pfn;
         static unsigned int smptrap=0;
         unsigned long delay = 0;
-       struct _lowcore *lowcore;
+       struct _lowcore *lc;
        int i;

         if (smptrap)
@@ -451,27 +451,26 @@
         /*
          * Setup lowcore for boot cpu
          */
-       lowcore = (struct _lowcore *)
-               __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
-       memset(lowcore, 0, PAGE_SIZE);
-       lowcore->restart_psw.mask = _RESTART_PSW_MASK;
-       lowcore->restart_psw.addr = _ADDR_31 + (addr_t) &restart_int_handler;
-       lowcore->external_new_psw.mask = _EXT_PSW_MASK;
-       lowcore->external_new_psw.addr = _ADDR_31 + (addr_t) &ext_int_handler;
-       lowcore->svc_new_psw.mask = _SVC_PSW_MASK;
-       lowcore->svc_new_psw.addr = _ADDR_31 + (addr_t) &system_call;
-       lowcore->program_new_psw.mask = _PGM_PSW_MASK;
-       lowcore->program_new_psw.addr = _ADDR_31 + (addr_t) &pgm_check_handler;
-        lowcore->mcck_new_psw.mask = _MCCK_PSW_MASK;
-       lowcore->mcck_new_psw.addr = _ADDR_31 + (addr_t) &mcck_int_handler;
-       lowcore->io_new_psw.mask = _IO_PSW_MASK;
-       lowcore->io_new_psw.addr = _ADDR_31 + (addr_t) &io_int_handler;
-       lowcore->ipl_device = S390_lowcore.ipl_device;
-       lowcore->kernel_stack = ((__u32) &init_thread_union) + 8192;
-       lowcore->async_stack = (__u32)
+       lc = (struct _lowcore *) __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
+       memset(lc, 0, PAGE_SIZE);
+       lc->restart_psw.mask = PSW_BASE_BITS;
+       lc->restart_psw.addr = PSW_ADDR_AMODE31 + (__u32) restart_int_handler;
+       lc->external_new_psw.mask = PSW_KERNEL_BITS;
+       lc->external_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) ext_int_handler;
+       lc->svc_new_psw.mask = PSW_KERNEL_BITS;
+       lc->svc_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) system_call;
+       lc->program_new_psw.mask = PSW_KERNEL_BITS;
+       lc->program_new_psw.addr = PSW_ADDR_AMODE31 + (__u32)pgm_check_handler;
+        lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
+       lc->mcck_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) mcck_int_handler;
+       lc->io_new_psw.mask = PSW_KERNEL_BITS;
+       lc->io_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) io_int_handler;
+       lc->ipl_device = S390_lowcore.ipl_device;
+       lc->kernel_stack = ((__u32) &init_thread_union) + 8192;
+       lc->async_stack = (__u32)
                __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0) + 8192;
-       lowcore->jiffy_timer = -1LL;
-       set_prefix((__u32) lowcore);
+       lc->jiffy_timer = -1LL;
+       set_prefix((__u32) lc);
         cpu_init();
         __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;

diff -urN linux-2.5.39/arch/s390/kernel/signal.c linux-2.5.39-s390/arch/s390/kernel/signal.c
--- linux-2.5.39/arch/s390/kernel/signal.c      Mon Sep 30 13:33:16 2002
+++ linux-2.5.39-s390/arch/s390/kernel/signal.c Mon Sep 30 13:33:16 2002
@@ -167,8 +167,8 @@
        int err;

        err = __copy_from_user(regs, &sregs->regs, sizeof(_s390_regs_common));
-       regs->psw.mask = _USER_PSW_MASK | (regs->psw.mask & PSW_MASK_DEBUGCHANGE);
-       regs->psw.addr |= _ADDR_31;
+       regs->psw.mask = PSW_USER_BITS | (regs->psw.mask & PSW_MASK_CC);
+       regs->psw.addr |= PSW_ADDR_AMODE31;
        if (err)
                return err;

@@ -298,9 +298,9 @@
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ka->sa.sa_flags & SA_RESTORER) {
-                regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+                regs->gprs[14] = (__u32) ka->sa.sa_restorer | PSW_ADDR_AMODE31;
        } else {
-                regs->gprs[14] = FIX_PSW(frame->retcode);
+                regs->gprs[14] = (__u32) frame->retcode | PSW_ADDR_AMODE31;
                if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
                               (u16 *)(frame->retcode)))
                        goto give_sigsegv;
@@ -311,12 +311,12 @@
                goto give_sigsegv;

        /* Set up registers for signal handler */
-       regs->gprs[15] = (addr_t)frame;
-       regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
-       regs->psw.mask = _USER_PSW_MASK;
+       regs->gprs[15] = (__u32) frame;
+       regs->psw.addr = (__u32) ka->sa.sa_handler | PSW_ADDR_AMODE31;
+       regs->psw.mask = PSW_USER_BITS;

        regs->gprs[2] = map_signal(sig);
-       regs->gprs[3] = (addr_t)&frame->sc;
+       regs->gprs[3] = (__u32) &frame->sc;

        /* We forgot to include these in the sigcontext.
           To avoid breaking binary compatibility, they are passed as args. */
@@ -356,9 +356,9 @@
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ka->sa.sa_flags & SA_RESTORER) {
-                regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+                regs->gprs[14] = (__u32) ka->sa.sa_restorer | PSW_ADDR_AMODE31;
        } else {
-                regs->gprs[14] = FIX_PSW(frame->retcode);
+                regs->gprs[14] = (__u32) frame->retcode | PSW_ADDR_AMODE31;
                err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
                                  (u16 *)(frame->retcode));
        }
@@ -368,13 +368,13 @@
                goto give_sigsegv;

        /* Set up registers for signal handler */
-       regs->gprs[15] = (addr_t)frame;
-       regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
-       regs->psw.mask = _USER_PSW_MASK;
+       regs->gprs[15] = (__u32) frame;
+       regs->psw.addr = (__u32) ka->sa.sa_handler | PSW_ADDR_AMODE31;
+       regs->psw.mask = PSW_USER_BITS;

        regs->gprs[2] = map_signal(sig);
-       regs->gprs[3] = (addr_t)&frame->info;
-       regs->gprs[4] = (addr_t)&frame->uc;
+       regs->gprs[3] = (__u32) &frame->info;
+       regs->gprs[4] = (__u32) &frame->uc;
        return;

 give_sigsegv:
diff -urN linux-2.5.39/arch/s390/kernel/traps.c linux-2.5.39-s390/arch/s390/kernel/traps.c
--- linux-2.5.39/arch/s390/kernel/traps.c       Mon Sep 30 13:25:21 2002
+++ linux-2.5.39-s390/arch/s390/kernel/traps.c  Mon Sep 30 13:33:16 2002
@@ -116,22 +116,22 @@
                stack = (unsigned long*)&stack;

        printk("Call Trace: ");
-       low_addr = ((unsigned long) stack) & PSW_ADDR_MASK;
+       low_addr = ((unsigned long) stack) & PSW_ADDR_INSN;
        high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
        /* Skip the first frame (biased stack) */
-       backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK;
+       backchain = *((unsigned long *) low_addr) & PSW_ADDR_INSN;
        /* Print up to 8 lines */
        for (i = 0; i < 8; i++) {
                if (backchain < low_addr || backchain >= high_addr)
                        break;
-               ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_MASK;
+               ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_INSN;
                if (!kernel_text_address(ret_addr))
                        break;
                if (i && ((i % 6) == 0))
                        printk("\n   ");
                printk("[<%08lx>] ", ret_addr);
                low_addr = backchain;
-               backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK;
+               backchain = *((unsigned long *) backchain) & PSW_ADDR_INSN;
        }
        printk("\n");
 }
@@ -184,7 +184,7 @@
        char *mode;
        int i;

-       mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl";
+       mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
        printk("%s PSW : %08lx %08lx\n",
               mode, (unsigned long) regs->psw.mask,
               (unsigned long) regs->psw.addr);
@@ -210,7 +210,7 @@
         * time of the fault.
         */
        old_fs = get_fs();
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                set_fs(USER_DS);
        else
                set_fs(KERNEL_DS);
@@ -287,10 +287,10 @@
         * We got all needed information from the lowcore and can
         * now safely switch on interrupts.
         */
-        if (regs->psw.mask & PSW_PROBLEM_STATE)
+        if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();

-        if (regs->psw.mask & PSW_PROBLEM_STATE) {
+        if (regs->psw.mask & PSW_MASK_PSTATE) {
                 struct task_struct *tsk = current;

                 tsk->thread.trap_no = interruption_code & 0xffff;
@@ -322,12 +322,12 @@

 static inline void *get_check_address(struct pt_regs *regs)
 {
-       return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
+       return (void *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
 }

 int do_debugger_trap(struct pt_regs *regs,int signal)
 {
-       if(regs->psw.mask&PSW_PROBLEM_STATE)
+       if(regs->psw.mask&PSW_MASK_PSTATE)
        {
                if(current->ptrace & PT_PTRACED)
                        force_sig(signal,current);
@@ -423,10 +423,10 @@
         * We got all needed information from the lowcore and can
         * now safely switch on interrupts.
         */
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();

-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                get_user(*((__u16 *) opcode), location);
        else
                *((__u16 *)opcode)=*((__u16 *)location);
@@ -436,7 +436,7 @@
                        signal = SIGILL;
        }
 #ifdef CONFIG_MATHEMU
-        else if (regs->psw.mask & PSW_PROBLEM_STATE)
+        else if (regs->psw.mask & PSW_MASK_PSTATE)
        {
                if (opcode[0] == 0xb3) {
                        get_user(*((__u16 *) (opcode+2)), location+1);
@@ -484,10 +484,10 @@
         * We got all needed information from the lowcore and can
         * now safely switch on interrupts.
         */
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();

-        if (regs->psw.mask & PSW_PROBLEM_STATE) {
+        if (regs->psw.mask & PSW_MASK_PSTATE) {
                get_user(*((__u16 *) opcode), location);
                switch (opcode[0]) {
                case 0x28: /* LDR Rx,Ry   */
@@ -547,7 +547,7 @@
         * We got all needed information from the lowcore and can
         * now safely switch on interrupts.
         */
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();

        if (MACHINE_HAS_IEEE)
@@ -555,7 +555,7 @@
                                  : "=m" (current->thread.fp_regs.fpc));

 #ifdef CONFIG_MATHEMU
-        else if (regs->psw.mask & PSW_PROBLEM_STATE) {
+        else if (regs->psw.mask & PSW_MASK_PSTATE) {
                __u8 opcode[6];
                get_user(*((__u16 *) opcode), location);
                switch (opcode[0]) {
@@ -679,21 +679,19 @@

 void handle_per_exception(struct pt_regs *regs)
 {
-       if(regs->psw.mask&PSW_PROBLEM_STATE)
-       {
+       if (regs->psw.mask & PSW_MASK_PSTATE) {
                per_struct *per_info=&current->thread.per_info;
                per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
                per_info->lowcore.words.address=S390_lowcore.per_address;
                per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
        }
-       if(do_debugger_trap(regs,SIGTRAP))
-       {
+       if (do_debugger_trap(regs,SIGTRAP)) {
                /* I've seen this possibly a task structure being reused ? */
                printk("Spurious per exception detected\n");
                printk("switching off per tracing for this task.\n");
                show_regs(regs);
                /* Hopefully switching off per tracing will help us survive */
-               regs->psw.mask &= ~PSW_PER_MASK;
+               regs->psw.mask &= ~PSW_MASK_PER;
        }
 }

diff -urN linux-2.5.39/arch/s390/mm/extable.c linux-2.5.39-s390/arch/s390/mm/extable.c
--- linux-2.5.39/arch/s390/mm/extable.c Fri Sep 27 23:49:07 2002
+++ linux-2.5.39-s390/arch/s390/mm/extable.c    Mon Sep 30 13:33:16 2002
@@ -48,7 +48,7 @@
         addr &= 0x7fffffff;  /* remove amode bit from address */
        /* There is only the kernel to search.  */
        ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
-       if (ret) ret = FIX_PSW(ret);
+       if (ret) ret = ret | PSW_ADDR_AMODE31;
        return ret;
 #else
        unsigned long flags;
@@ -63,7 +63,7 @@
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end - 1, addr);
                if (ret) {
-                       ret = FIX_PSW(ret);
+                       ret = ret | PSW_ADDR_AMODE31;
                        break;
                }
        }
diff -urN linux-2.5.39/arch/s390/mm/fault.c linux-2.5.39-s390/arch/s390/mm/fault.c
--- linux-2.5.39/arch/s390/mm/fault.c   Mon Sep 30 13:33:09 2002
+++ linux-2.5.39-s390/arch/s390/mm/fault.c      Mon Sep 30 13:33:16 2002
@@ -167,7 +167,7 @@

                /* Low-address protection hit in kernel mode means
                   NULL pointer write access in kernel mode.  */
-               if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
+               if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
                        address = 0;
                        user_address = 0;
                        goto no_context;
@@ -259,7 +259,7 @@
         up_read(&mm->mmap_sem);

         /* User mode accesses just cause a SIGSEGV */
-        if (regs->psw.mask & PSW_PROBLEM_STATE) {
+        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);
@@ -299,7 +299,7 @@
                goto survive;
        }
        printk("VM: killing process %s\n", tsk->comm);
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                do_exit(SIGKILL);
        goto no_context;

@@ -315,7 +315,7 @@
        force_sig(SIGBUS, tsk);

        /* Kernel mode? Handle exceptions or die */
-       if (!(regs->psw.mask & PSW_PROBLEM_STATE))
+       if (!(regs->psw.mask & PSW_MASK_PSTATE))
                goto no_context;
 }

@@ -394,7 +394,7 @@
                 spin_unlock(&pseudo_wait_spinlock);
         } else {
                 /* Pseudo page faults in kernel mode is a bad idea */
-                if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
+                if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
                         /*
                         * VM presents pseudo page faults if the interrupted
                         * state was not disabled for interrupts. So we can
@@ -529,7 +529,7 @@
         * We got all needed information from the lowcore and can
         * now safely switch on interrupts.
         */
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();

        if (subcode & 0x0080) {
diff -urN linux-2.5.39/arch/s390x/kernel/linux32.h linux-2.5.39-s390/arch/s390x/kernel/linux32.h
--- linux-2.5.39/arch/s390x/kernel/linux32.h    Fri Sep 27 23:50:34 2002
+++ linux-2.5.39-s390/arch/s390x/kernel/linux32.h       Mon Sep 30 13:33:16 2002
@@ -8,8 +8,6 @@
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/export.h>

-#ifdef CONFIG_S390_SUPPORT
-
 /* Macro that masks the high order bit of an 32 bit pointer and converts it*/
 /*       to a 64 bit pointer */
 #define A(__x) ((unsigned long)((__x) & 0x7FFFFFFFUL))
@@ -194,6 +192,32 @@
         __u32  addr;
 } _psw_t32 __attribute__ ((aligned(8)));

+#define PSW32_MASK_PER         0x40000000UL
+#define PSW32_MASK_DAT         0x04000000UL
+#define PSW32_MASK_IO          0x02000000UL
+#define PSW32_MASK_EXT         0x01000000UL
+#define PSW32_MASK_KEY         0x00F00000UL
+#define PSW32_MASK_MCHECK      0x00040000UL
+#define PSW32_MASK_WAIT                0x00020000UL
+#define PSW32_MASK_PSTATE      0x00010000UL
+#define PSW32_MASK_ASC         0x0000C000UL
+#define PSW32_MASK_CC          0x00003000UL
+#define PSW32_MASK_PM          0x00000f00UL
+
+#define PSW32_ADDR_AMODE31     0x80000000UL
+#define PSW32_ADDR_INSN                0x7FFFFFFFUL
+
+#define PSW32_BASE_BITS                0x00080000UL
+
+#define PSW32_ASC_PRIMARY      0x00000000UL
+#define PSW32_ASC_ACCREG       0x00004000UL
+#define PSW32_ASC_SECONDARY    0x00008000UL
+#define PSW32_ASC_HOME         0x0000C000UL
+
+#define PSW32_USER_BITS        (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
+                        PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
+                        PSW32_MASK_PSTATE)
+
 typedef struct
 {
        _psw_t32        psw;
@@ -241,6 +265,4 @@
        sigset_t32              uc_sigmask;     /* mask last for extensibility */
 };

-#endif /* !CONFIG_S390_SUPPORT */
-
 #endif /* _ASM_S390X_S390_H */
diff -urN linux-2.5.39/arch/s390x/kernel/process.c linux-2.5.39-s390/arch/s390x/kernel/process.c
--- linux-2.5.39/arch/s390x/kernel/process.c    Mon Sep 30 13:33:16 2002
+++ linux-2.5.39-s390/arch/s390x/kernel/process.c       Mon Sep 30 13:33:16 2002
@@ -75,9 +75,10 @@

        /*
         * Wait for external, I/O or machine check interrupt and
-        * switch of machine check bit after the wait has ended.
+        * switch off machine check bit after the wait has ended.
         */
-       wait_psw.mask = _WAIT_PSW_MASK;
+       wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
+               PSW_MASK_IO | PSW_MASK_EXT;
        asm volatile (
                "    larl  %0,0f\n"
                "    stg   %0,8(%1)\n"
@@ -111,7 +112,7 @@

        show_registers(regs);
        /* Show stack backtrace if pt_regs is from kernel mode */
-       if (!(regs->psw.mask & PSW_PROBLEM_STATE))
+       if (!(regs->psw.mask & PSW_MASK_PSTATE))
                show_trace((unsigned long *) regs->gprs[15]);
 }

@@ -132,7 +133,7 @@
        struct pt_regs regs;

        memset(&regs, 0, sizeof(regs));
-       regs.psw.mask = _SVC_PSW_MASK;
+       regs.psw.mask = PSW_KERNEL_BITS;
        regs.psw.addr = (__u64) kernel_thread_starter;
        regs.gprs[7] = STACK_FRAME_OVERHEAD;
        regs.gprs[8] = __LC_KERNEL_STACK;
diff -urN linux-2.5.39/arch/s390x/kernel/ptrace.c linux-2.5.39-s390/arch/s390x/kernel/ptrace.c
--- linux-2.5.39/arch/s390x/kernel/ptrace.c     Fri Sep 27 23:49:05 2002
+++ linux-2.5.39-s390/arch/s390x/kernel/ptrace.c        Mon Sep 30 13:33:16 2002
@@ -4,6 +4,7 @@
  *  S390 version
  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Denis Joseph Barrow (djbar...@de.ibm.com,barrow...@yahoo.com),
+ *               Martin Schwidefsky (schwidef...@de.ibm.com)
  *
  *  Based on PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (g...@linuxppc.org)
@@ -38,49 +39,48 @@
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+
 #ifdef CONFIG_S390_SUPPORT
-#include "linux32.h"
-#else
-#define parent_31bit 0
+#include "ptrace32.h"
 #endif

-
-void FixPerRegisters(struct task_struct *task)
+static void FixPerRegisters(struct task_struct *task)
 {
-       struct pt_regs *regs = __KSTK_PTREGS(task);
-       per_struct *per_info=
-                       (per_struct *)&task->thread.per_info;
+       struct pt_regs *regs;
+       per_struct *per_info;

+       regs = __KSTK_PTREGS(task);
+       per_info = (per_struct *) &task->thread.per_info;
        per_info->control_regs.bits.em_instruction_fetch =
-               per_info->single_step | per_info->instruction_fetch;
+               per_info->single_step | per_info->instruction_fetch;

        if (per_info->single_step) {
-               per_info->control_regs.bits.starting_addr=0;
+               per_info->control_regs.bits.starting_addr = 0;
 #ifdef CONFIG_S390_SUPPORT
-               if (current->thread.flags & S390_FLAG_31BIT) {
-                       per_info->control_regs.bits.ending_addr=0x7fffffffUL;
-               }
-               else
-#endif      
-               {
-               per_info->control_regs.bits.ending_addr=-1L;
-               }
+               if (current->thread.flags & S390_FLAG_31BIT)
+                       per_info->control_regs.bits.ending_addr = 0x7fffffffUL;
+               else
+#endif
+                       per_info->control_regs.bits.ending_addr = -1;
        } else {
-               per_info->control_regs.bits.starting_addr=
-                       per_info->starting_addr;
-               per_info->control_regs.bits.ending_addr=
-                       per_info->ending_addr;
+               per_info->control_regs.bits.starting_addr =
+                       per_info->starting_addr;
+               per_info->control_regs.bits.ending_addr =
+                       per_info->ending_addr;
        }
-       /* if any of the control reg tracing bits are on
-          we switch on per in the psw */
+       /*
+        * if any of the control reg tracing bits are on
+        * we switch on per in the psw
+        */
        if (per_info->control_regs.words.cr[0] & PER_EM_MASK)
-               regs->psw.mask |= PSW_PER_MASK;
+               regs->psw.mask |= PSW_MASK_PER;
        else
-               regs->psw.mask &= ~PSW_PER_MASK;
-       if (per_info->control_regs.bits.storage_alt_space_ctl)
-               task->thread.user_seg |= USER_STD_MASK;
+               regs->psw.mask &= ~PSW_MASK_PER;
+
+       if (per_info->control_regs.bits.em_storage_alteration)
+               per_info->control_regs.bits.storage_alt_space_ctl = 1;
        else
-               task->thread.user_seg &= ~USER_STD_MASK;
+               per_info->control_regs.bits.storage_alt_space_ctl = 0;
 }

 void set_single_step(struct task_struct *task)
@@ -99,424 +99,406 @@
        FixPerRegisters (task);
 }

-int ptrace_usercopy(addr_t realuseraddr, addr_t copyaddr, int len,
-                    int tofromuser, int writeuser, unsigned long mask)
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
 {
-        unsigned long *realuserptr, *copyptr;
-       unsigned long tempuser;
-       int retval;
-
-        retval = 0;
-        realuserptr = (unsigned long *) realuseraddr;
-        copyptr = (unsigned long *) copyaddr;
+       /* make sure the single step bit is not set. */
+       clear_single_step(child);
+}

-       if (writeuser && realuserptr == NULL)
-               return 0;
+/*
+ * Read the word at offset addr from the user area of a process. The
+ * trouble here is that the information is littered over different
+ * locations. The process registers are found on the kernel stack,
+ * the floating point stuff and the trace settings are stored in
+ * the task structure. In addition the different structures in
+ * struct user contain pad bytes that should be read as zeroes.
+ * Lovely...
+ */
+static int peek_user(struct task_struct *child, addr_t addr, addr_t data)
+{
+       struct user *dummy = NULL;
+       addr_t offset;
+       __u64 tmp;
+
+       if ((addr & 7) || addr > sizeof(struct user) - 7)
+               return -EIO;
+
+       if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
+               /*
+                * psw, gprs, acrs and orig_gpr2 are stored on the stack
+                */
+               tmp = *(__u64 *)((addr_t) __KSTK_PTREGS(child) + addr);
+
+       } else if (addr >= (addr_t) &dummy->regs.fp_regs &&
+                  addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
+               /*
+                * floating point regs. are stored in the thread structure
+                */
+               offset = addr - (addr_t) &dummy->regs.fp_regs;
+               tmp = *(__u64 *)((addr_t) &child->thread.fp_regs + offset);
+
+       } else if (addr >= (addr_t) &dummy->regs.per_info &&
+                  addr < (addr_t) (&dummy->regs.per_info + 1)) {
+               /*
+                * per_info is found in the thread structure
+                */
+               offset = addr - (addr_t) &dummy->regs.per_info;
+               tmp = *(__u64 *)((addr_t) &child->thread.per_info + offset);

-       if (mask != -1L) {
-               tempuser = *realuserptr;
-               if (!writeuser) {
-                       tempuser &= mask;
-                       realuserptr = &tempuser;
-               }
-       }
-       if (tofromuser) {
-               if (writeuser) {
-                       retval = copy_from_user(realuserptr, copyptr, len);
-               } else {
-                       if (realuserptr == NULL)
-                               retval = clear_user(copyptr, len);
-                       else
-                               retval = copy_to_user(copyptr,realuserptr,len);
-                        retval = retval ? -EIO : 0;
-               }      
-       } else {
-               if (writeuser)
-                       memcpy(realuserptr, copyptr, len);
-               else
-                       memcpy(copyptr, realuserptr, len);
-       }
-       if (mask != -1L && writeuser)
-                *realuserptr = (*realuserptr & mask) | (tempuser & ~mask);
-       return retval;
-}
+       } else
+               tmp = 0;

-#ifdef CONFIG_S390_SUPPORT
+       return put_user(tmp, (__u64 *) data);
+}

-typedef struct
+/*
+ * Write a word to the user area of a process at location addr. This
+ * operation does have an additional problem compared to peek_user.
+ * Stores to the program status word and on the floating point
+ * control register needs to get checked for validity.
+ */
+static int poke_user(struct task_struct *child, addr_t addr, addr_t data)
 {
-       __u32 cr[3];
-} per_cr_words32  __attribute__((packed));
+       struct user *dummy = NULL;
+       addr_t offset;

-typedef struct
-{
-       __u16          perc_atmid;          /* 0x096 */
-       __u32          address;             /* 0x098 */
-       __u8           access_id;           /* 0x0a1 */
-} per_lowcore_words32  __attribute__((packed));
+       if ((addr & 7) || addr > sizeof(struct user) - 7)
+               return -EIO;

-typedef struct
-{
-       union {
-               per_cr_words32   words;
-       } control_regs  __attribute__((packed));
-       /*
-        * Use these flags instead of setting em_instruction_fetch
-        * directly they are used so that single stepping can be
-        * switched on & off while not affecting other tracing
-        */
-       unsigned  single_step       : 1;
-       unsigned  instruction_fetch : 1;
-       unsigned                    : 30;
-       /*
-        * These addresses are copied into cr10 & cr11 if single
-        * stepping is switched off
-        */
-       __u32     starting_addr;
-       __u32     ending_addr;
-       union {
-               per_lowcore_words32 words;
-       } lowcore;
-} per_struct32 __attribute__((packed));
-
-struct user_regs_struct32
-{
-       _psw_t32 psw;
-       u32 gprs[NUM_GPRS];
-       u32 acrs[NUM_ACRS];
-       u32 orig_gpr2;
-       s390_fp_regs fp_regs;
-       /*
-        * These per registers are in here so that gdb can modify them
-        * itself as there is no "official" ptrace interface for hardware
-        * watchpoints. This is the way intel does it.
-        */
-       per_struct32 per_info;
-       u32  ieee_instruction_pointer;
-       /* Used to give failing instruction back to user for ieee exceptions */
-};
-
-struct user32 {
-                                  /* We start with the registers, to mimic the way that "memory" is returned
-                                   from the ptrace(3,...) function.  */
-  struct user_regs_struct32 regs; /* Where the registers are actually stored */
-                                  /* The rest of this junk is to help gdb figure out what goes where */
-  u32 u_tsize;                   /* Text segment size (pages). */
-  u32 u_dsize;                   /* Data segment size (pages). */
-  u32 u_ssize;                   /* Stack segment size (pages). */
-  u32 start_code;                 /* Starting virtual address of text. */
-  u32 start_stack;               /* Starting virtual address of stack area.
-                                  This is actually the bottom of the stack,
-                                  the top of the stack is always found in the
-                                  esp register.  */
-  s32 signal;                    /* Signal that caused the core dump. */
-  u32 u_ar0;                      /* Used by gdb to help find the values for */
-                                 /* the registers. */
-  u32 magic;                     /* To uniquely identify a core file */
-  char u_comm[32];               /* User command that was responsible */
-};
-
-
-#define PT32_PSWMASK  0x0
-#define PT32_PSWADDR  0x04
-#define PT32_GPR0     0x08
-#define PT32_GPR15    0x44
-#define PT32_ACR0     0x48
-#define PT32_ACR15    0x84
-#define PT32_ORIGGPR2 0x88
-#define PT32_FPC      0x90
-#define PT32_FPR0_HI  0x98
-#define PT32_FPR15_LO 0x114
-#define PT32_CR_9     0x118
-#define PT32_CR_11    0x120
-#define PT32_IEEE_IP  0x13C
-#define PT32_LASTOFF  PT32_IEEE_IP
-#define PT32_ENDREGS  0x140-1
-#define U32OFFSETOF(member) offsetof(struct user32,regs.member)
-#define U64OFFSETOF(member) offsetof(struct user,regs.member)
-#define U6432DIFF(member) (U64OFFSETOF(member) - U32OFFSETOF(member))
-#define PT_SINGLE_STEP   (PT_CR_11+8)
-#define PT32_SINGLE_STEP (PT32_CR_11+4)
-
-#endif /* CONFIG_S390_SUPPORT */
-
-int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr,
-              int len, int tofromuser, int writingtouser)
-{
-       int copylen=0,copymax;
-       addr_t  realuseraddr;
-       saddr_t enduseraddr;
-       unsigned long mask;
-#ifdef CONFIG_S390_SUPPORT
-       int     parent_31bit=current->thread.flags & S390_FLAG_31BIT;
-       int     skip;
-#endif
-       enduseraddr=useraddr+len;
-       if ((useraddr<0||useraddr&3||enduseraddr&3)||
-#ifdef CONFIG_S390_SUPPORT
-           (parent_31bit && enduseraddr > sizeof(struct user32)) ||
-#endif
-           enduseraddr > sizeof(struct user))
-               return (-EIO);
+       if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
+               /*
+                * psw, gprs, acrs and orig_gpr2 are stored on the stack
+                */
+               if (addr == (addr_t) &dummy->regs.psw.mask &&
+#ifdef CONFIG_S390_SUPPORT
+                   (data & ~PSW_MASK_CC) != PSW_USER32_BITS &&
+#endif
+                   (data & ~PSW_MASK_CC) != PSW_USER_BITS)
+                       /* Invalid psw mask. */
+                       return -EINVAL;
+               *(__u64 *)((addr_t) __KSTK_PTREGS(child) + addr) = data;
+
+       } else if (addr >= (addr_t) &dummy->regs.fp_regs &&
+                  addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
+               /*
+                * floating point regs. are stored in the thread structure
+                */
+               if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
+                   ((data >> 32) & ~FPC_VALID_MASK) != 0)
+                       /* Invalid floating pointer control. */
+                       return -EINVAL;
+               offset = addr - (addr_t) &dummy->regs.fp_regs;
+               *(__u64 *)((addr_t) &child->thread.fp_regs + offset) = data;
+
+       } else if (addr >= (addr_t) &dummy->regs.per_info &&
+                  addr < (addr_t) (&dummy->regs.per_info + 1)) {
+               /*
+                * per_info is found in the thread structure
+                */
+               offset = addr - (addr_t) &dummy->regs.per_info;
+               *(__u64 *)((addr_t) &child->thread.per_info + offset) = data;

-#ifdef CONFIG_S390_SUPPORT
-       if(parent_31bit)
-       {
-               if(useraddr != PT32_PSWMASK)
-               {
-                       if (useraddr == PT32_PSWADDR)
-                               useraddr = PT_PSWADDR+4;
-                       else if(useraddr <= PT32_GPR15)
-                               useraddr = ((useraddr-PT32_GPR0)*2) + PT_GPR0+4;
-                       else if(useraddr <= PT32_ACR15)
-                               useraddr += PT_ACR0-PT32_ACR0;
-                       else if(useraddr == PT32_ORIGGPR2)
-                               useraddr = PT_ORIGGPR2+4;
-                       else if(useraddr <= PT32_FPR15_LO)
-                               useraddr += PT_FPR0-PT32_FPR0_HI;
-                       else if(useraddr <= PT32_CR_11)
-                               useraddr = ((useraddr-PT32_CR_9)*2) + PT_CR_9+4;
-                       else if(useraddr ==  PT32_SINGLE_STEP)
-                               useraddr = PT_SINGLE_STEP;
-                       else if(useraddr <= U32OFFSETOF(per_info.ending_addr))      
-                               useraddr = (((useraddr-U32OFFSETOF(per_info.starting_addr)))*2) +
-                                       U64OFFSETOF(per_info.starting_addr)+4;
-                       else if( useraddr == U32OFFSETOF(per_info.lowcore.words.perc_atmid))
-                               useraddr = U64OFFSETOF(per_info.lowcore.words.perc_atmid);
-                       else if( useraddr == U32OFFSETOF(per_info.lowcore.words.address))
-                               useraddr = U64OFFSETOF(per_info.lowcore.words.address)+4;
-                       else if(useraddr == U32OFFSETOF(per_info.lowcore.words.access_id))
-                               useraddr = U64OFFSETOF(per_info.lowcore.words.access_id);
-                       else if(useraddr == PT32_IEEE_IP)
-                               useraddr = PT_IEEE_IP+4;
-               }
        }
-#endif /* CONFIG_S390_SUPPORT */

-       while(len>0)
-       {
-#ifdef CONFIG_S390_SUPPORT
-               skip=0;
-#endif
-               mask=PSW_ADDR_MASK;
-               if(useraddr<PT_FPC)
-               {
-                       realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr;
-                       if(useraddr<(PT_PSWMASK+8))
-                       {
-                               if(parent_31bit)
-                               {
-                                       copymax=PT_PSWMASK+4;
-#ifdef CONFIG_S390_SUPPORT
-                                       skip=8;
-#endif
-                               }
-                               else
-                               {
-                                       copymax=PT_PSWMASK+8;
-                               }
-                               if(writingtouser)
-                                       mask=PSW_MASK_DEBUGCHANGE;
-                       }
-                       else if(useraddr<(PT_PSWADDR+8))
-                       {
-                               copymax=PT_PSWADDR+8;
-                               mask=PSW_ADDR_DEBUGCHANGE;
-#ifdef CONFIG_S390_SUPPORT
-                               if(parent_31bit)
-                                       skip=4;
-#endif
+       FixPerRegisters(child);
+       return 0;
+}

-                       }
-                       else
-                       {
-#ifdef CONFIG_S390_SUPPORT
-                               if(parent_31bit && useraddr <= PT_GPR15+4)
-                               {
-                                       copymax=useraddr+4;
-                                       if(useraddr<PT_GPR15+4)
-                                               skip=4;
-                               }
-                               else
-#endif
-                                       copymax=PT_FPC;
-                       }
-               }
-               else if(useraddr<(PT_FPR15+sizeof(freg_t)))
-               {
-                       copymax=(PT_FPR15+sizeof(freg_t));
-                       realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]);
-               }
-               else if(useraddr<sizeof(struct user_regs_struct))
-               {
-#ifdef CONFIG_S390_SUPPORT
-                       if( parent_31bit && useraddr <= PT_IEEE_IP+4)
-                       {
-                               switch(useraddr)
-                               {
-                               case PT_CR_11+4:
-                               case U64OFFSETOF(per_info.ending_addr)+4:
-                               case U64OFFSETOF(per_info.lowcore.words.address)+4:
-                                       copymax=useraddr+4;
-                                       break;
-                               case  PT_SINGLE_STEP:
-                               case  U64OFFSETOF(per_info.lowcore.words.perc_atmid):
-                                       /* We copy 2 bytes in excess for the atmid member this also gets around */
-                                       /* alignment for this member in 32 bit */
-                                       skip=8;
-                                       copymax=useraddr+4;
-                                       break;
-                               default:
-                                       copymax=useraddr+4;
-                                       skip=4;
-                               }
-                       }
+static int
+do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
+{
+       unsigned long tmp;
+       ptrace_area parea;
+       int copied, ret;
+
+       switch (request) {
+       case PTRACE_PEEKTEXT:
+       case PTRACE_PEEKDATA:
+               /* read word at location addr. */
+               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+               if (copied != sizeof(tmp))
+                       return -EIO;
+               return put_user(tmp, (unsigned long *) data);
+
+       case PTRACE_PEEKUSR:
+               /* read the word at location addr in the USER area. */
+               return peek_user(child, addr, data);
+
+       case PTRACE_POKETEXT:
+       case PTRACE_POKEDATA:
+               /* write the word at location addr. */
+               copied = access_process_vm(child, addr, &data, sizeof(data),1);
+               if (copied != sizeof(data))
+                       return -EIO;
+               return 0;
+
+       case PTRACE_POKEUSR:
+               /* write the word at location addr in the USER area */
+               return poke_user(child, addr, data);
+
+       case PTRACE_PEEKUSR_AREA:
+       case PTRACE_POKEUSR_AREA:
+               if (!copy_from_user(&parea, (void *) addr, sizeof(parea)))
+                       return -EFAULT;
+               addr = parea.kernel_addr;
+               data = parea.process_addr;
+               copied = 0;
+               while (copied < parea.len) {
+                       if (request == PTRACE_PEEKUSR_AREA)
+                               ret = peek_user(child, addr, data);
                        else
-#endif
-                       {
-                               copymax=sizeof(struct user_regs_struct);
-                       }
-                       realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
-               }
-               else
-               {
-                       copymax=sizeof(struct user);
-                       realuseraddr=(addr_t)NULL;
+                               ret = poke_user(child, addr, data);
+                       if (ret)
+                               return ret;
+                       addr += sizeof(unsigned long);
+                       data += sizeof(unsigned long);
+                       copied += sizeof(unsigned long);
                }
-               copylen=copymax-useraddr;
-               copylen=(copylen>len ? len:copylen);
-               if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask))
-                       return (-EIO);
-               copyaddr+=copylen;
-               len-=copylen;
-               useraddr+=copylen
-#if CONFIG_S390_SUPPORT
-                       +skip
-#endif
-                       ;
+               return 0;
        }
-       FixPerRegisters(task);
-       return(0);
+       return -EIO;
 }

+#ifdef CONFIG_S390_SUPPORT
 /*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure single step bits etc are not set.
+ * Now the fun part starts... a 31 bit program running in the
+ * 31 bit emulation tracing another program. PTRACE_PEEKTEXT,
+ * PTRACE_PEEKDATA, PTRACE_POKETEXT and PTRACE_POKEDATA are easy
+ * to handle, the difference to the 64 bit versions of the requests
+ * is that the access is done in multiples of 4 byte instead of
+ * 8 bytes (sizeof(unsigned long) on 31/64 bit).
+ * The ugly part are PTRACE_PEEKUSR, PTRACE_PEEKUSR_AREA,
+ * PTRACE_POKEUSR and PTRACE_POKEUSR_AREA. If the traced program
+ * is a 31 bit program too, the content of struct user can be
+ * emulated. A 31 bit program peeking into the struct user of
+ * a 64 bit program is a no-no.
  */
-void ptrace_disable(struct task_struct *child)
+
+/*
+ * Same as peek_user but for a 31 bit program.
+ */
+static int peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
 {
-       /* make sure the single step bit is not set. */
-       clear_single_step(child);
+       struct user32 *dummy32 = NULL;
+       per_struct32 *dummy_per32 = NULL;
+       addr_t offset;
+       __u32 tmp;
+
+       if (!(child->thread.flags & S390_FLAG_31BIT) ||
+           (addr & 3) || addr > sizeof(struct user) - 3)
+               return -EIO;
+
+       if (addr <= (addr_t) &dummy32->regs.orig_gpr2) {
+               /*
+                * psw, gprs, acrs and orig_gpr2 are stored on the stack
+                */
+               if (addr == (addr_t) &dummy32->regs.psw.mask) {
+                       /* Fake a 31 bit psw mask. */
+                       tmp = (__u32)(__KSTK_PTREGS(child)->psw.mask >> 32);
+                       tmp = (tmp & PSW32_MASK_CC) | PSW32_USER_BITS;
+               } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
+                       /* Fake a 31 bit psw address. */
+                       tmp = (__u32) __KSTK_PTREGS(child)->psw.addr |
+                               PSW32_ADDR_AMODE31;
+               } else
+                       tmp = *(__u32 *)((addr_t) __KSTK_PTREGS(child) +
+                                        addr*2 + 4);
+       } else if (addr >= (addr_t) &dummy32->regs.fp_regs &&
+                  addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
+               /*
+                * floating point regs. are stored in the thread structure
+                */
+               offset = addr - (addr_t) &dummy32->regs.fp_regs;
+               tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset);
+
+       } else if (addr >= (addr_t) &dummy32->regs.per_info &&
+                  addr < (addr_t) (&dummy32->regs.per_info + 1)) {
+               /*
+                * per_info is found in the thread structure
+                */
+               offset = addr - (addr_t) &dummy32->regs.per_info;
+               /* This is magic. See per_struct and per_struct32. */
+               if ((offset >= (addr_t) &dummy_per32->control_regs &&
+                    offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
+                   (offset >= (addr_t) &dummy_per32->starting_addr &&
+                    offset <= (addr_t) &dummy_per32->ending_addr) ||
+                   offset == (addr_t) &dummy_per32->lowcore.words.address)
+                       offset = offset*2 + 4;
+               else
+                       offset = offset*2;
+               tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset);
+
+       } else
+               tmp = 0;
+
+       return put_user(tmp, (__u32 *) data);
 }

-typedef struct
+/*
+ * Same as poke_user but for a 31 bit program.
+ */
+static int poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
 {
-__u32  len;
-__u32  kernel_addr;
-__u32  process_addr;
-} ptrace_area_emu31;
+       struct user32 *dummy32 = NULL;
+       per_struct32 *dummy_per32 = NULL;
+       addr_t offset;
+       __u32 tmp;
+       int ret;
+
+       if (!(child->thread.flags & S390_FLAG_31BIT) ||
+           (addr & 3) || addr > sizeof(struct user32) - 3)
+               return -EIO;
+
+       tmp = (__u32) data;
+
+       if (addr <= (addr_t) &dummy32->regs.orig_gpr2) {
+               /*
+                * psw, gprs, acrs and orig_gpr2 are stored on the stack
+                */
+               if (addr == (addr_t) &dummy32->regs.psw.mask) {
+                       /* Build a 64 bit psw mask from 31 bit mask. */
+                       if ((tmp & ~PSW32_MASK_CC) != PSW32_USER_BITS)
+                               /* Invalid psw mask. */
+                               return -EINVAL;
+                       __KSTK_PTREGS(child)->psw.mask = PSW_USER_BITS |
+                               ((tmp & PSW32_MASK_CC) << 32);
+               } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
+                       /* Build a 64 bit psw address from 31 bit address. */
+                       __KSTK_PTREGS(child)->psw.addr =
+                               (__u64) tmp & PSW32_ADDR_INSN;
+               } else
+                       *(__u32*)((addr_t) __KSTK_PTREGS(child) + addr*2 + 4) =
+                               tmp;
+       } else if (addr >= (addr_t) &dummy32->regs.fp_regs &&
+                  addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
+               /*
+                * floating point regs. are stored in the thread structure
+                */
+               if (addr == (addr_t) &dummy32->regs.fp_regs.fpc &&
+                   (tmp & ~FPC_VALID_MASK) != 0)
+                       /* Invalid floating pointer control. */
+                       return -EINVAL;
+               offset = addr - (addr_t) &dummy32->regs.fp_regs;
+               *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp;
+
+       } else if (addr >= (addr_t) &dummy32->regs.per_info &&
+                  addr < (addr_t) (&dummy32->regs.per_info + 1)) {
+               /*
+                * per_info is found in the thread structure.
+                */
+               offset = addr - (addr_t) &dummy32->regs.per_info;
+               /*
+                * This is magic. See per_struct and per_struct32.
+                * By incident the offsets in per_struct are exactly
+                * twice the offsets in per_struct32 for all fields.
+                * The 8 byte fields need special handling though,
+                * because the second half (bytes 4-7) is needed and
+                * not the first half.
+                */
+               if ((offset >= (addr_t) &dummy_per32->control_regs &&
+                    offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
+                   (offset >= (addr_t) &dummy_per32->starting_addr &&
+                    offset <= (addr_t) &dummy_per32->ending_addr) ||
+                   offset == (addr_t) &dummy_per32->lowcore.words.address)
+                       offset = offset*2 + 4;
+               else
+                       offset = offset*2;
+               *(__u32 *)((addr_t) &child->thread.per_info + offset) = tmp;

+       }

-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+       FixPerRegisters(child);
+       return 0;
+}
+
+static int
+do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
 {
-       struct task_struct *child;
-       int ret = -EPERM;
-       int copied;
-#ifdef CONFIG_S390_SUPPORT
-       int           parent_31bit;
-       int           sizeof_parent_long;
-       u8            *dataptr;
-#else
-#define sizeof_parent_long 8
-#define dataptr (u8 *)&data
-#endif
-       lock_kernel();
-       if (request == PTRACE_TRACEME)
-       {
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED)
-                       goto out;
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
-               ret = 0;
-               goto out;
-       }
-       ret = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (!child)
-               goto out;
-       ret = -EPERM;
-       if (pid == 1)           /* you may not mess with init */
-               goto out_tsk;
-       if (request == PTRACE_ATTACH)
-       {
-               ret = ptrace_attach(child);
-               goto out_tsk;
-       }
-       ret = -ESRCH;
-       // printk("child=%lX child->flags=%lX",child,child->flags);
-       /* I added child!=current line so we can get the */
-       /* ieee_instruction_pointer from the user structure DJB */
-       if(child!=current)
-       {
-               if (!(child->ptrace & PT_PTRACED))
-                       goto out_tsk;
-               if (child->state != TASK_STOPPED)
-               {
-                       if (request != PTRACE_KILL)
-                               goto out_tsk;
+       unsigned int tmp;  /* 4 bytes !! */
+       ptrace_area_emu31 parea;
+       int copied, ret;
+
+       switch (request) {
+       case PTRACE_PEEKTEXT:
+       case PTRACE_PEEKDATA:
+               /* read word at location addr. */
+               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+               if (copied != sizeof(tmp))
+                       return -EIO;
+               return put_user(tmp, (unsigned int *) data);
+
+       case PTRACE_PEEKUSR:
+               /* read the word at location addr in the USER area. */
+               return peek_user_emu31(child, addr, data);
+
+       case PTRACE_POKETEXT:
+       case PTRACE_POKEDATA:
+               /* write the word at location addr. */
+               tmp = data;
+               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
+               if (copied != sizeof(tmp))
+                       return -EIO;
+               return 0;
+
+       case PTRACE_POKEUSR:
+               /* write the word at location addr in the USER area */
+               return poke_user_emu31(child, addr, data);
+
+       case PTRACE_PEEKUSR_AREA:
+       case PTRACE_POKEUSR_AREA:
+               if (!copy_from_user(&parea, (void *) addr, sizeof(parea)))
+                       return -EFAULT;
+               addr = parea.kernel_addr;
+               data = parea.process_addr;
+               copied = 0;
+               while (copied < parea.len) {
+                       if (request == PTRACE_PEEKUSR_AREA)
+                               ret = peek_user_emu31(child, addr, data);
+                       else
+                               ret = poke_user_emu31(child, addr, data);
+                       if (ret)
+                               return ret;
+                       addr += sizeof(unsigned int);
+                       data += sizeof(unsigned int);
+                       copied += sizeof(unsigned int);
                }
-               if (child->parent != current)
-                       goto out_tsk;
+               return 0;
        }
-#ifdef CONFIG_S390_SUPPORT
-       parent_31bit=(current->thread.flags & S390_FLAG_31BIT);
-       sizeof_parent_long=(parent_31bit ? 4:8);
-       dataptr=&(((u8 *)&data)[parent_31bit ? 4:0]);
+       return -EIO;
+}
 #endif
-       switch (request)
-       {
-               /* If I and D space are separate, these will need to be fixed. */
-       case PTRACE_PEEKTEXT: /* read word at location addr. */
-       case PTRACE_PEEKDATA:
-       {
-               u8 tmp[8];
-               copied = access_process_vm(child, addr, tmp, sizeof_parent_long, 0);
-               ret = -EIO;
-               if (copied != sizeof_parent_long)
-                       break;
-               ret = copy_to_user((void *)data,tmp,sizeof_parent_long);
-               break;
-      
+
+static int
+do_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+       int ret;
+
+       if (request == PTRACE_ATTACH)
+               return ptrace_attach(child);
+
+       /*
+        * I added child != current line so we can get the
+        * ieee_instruction_pointer from the user structure DJB
+        */
+       if (child != current) {
+               ret = ptrace_check_attach(child, request == PTRACE_KILL);
+               if (ret < 0)
+                       return ret;
        }
-               /* read the word at location addr in the USER area. */
-       case PTRACE_PEEKUSR:
-               ret=copy_user(child,addr,data,sizeof_parent_long,1,0);
-               break;

-               /* If I and D space are separate, this will have to be fixed. */
-       case PTRACE_POKETEXT: /* write the word at location addr. */
-       case PTRACE_POKEDATA:
-               ret = 0;
-               if (access_process_vm(child, addr,dataptr, sizeof_parent_long, 1) == sizeof_parent_long)
-                       break;
-               ret = -EIO;
-               break;
-
-       case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-               ret=copy_user(child,addr,(addr_t)dataptr,sizeof_parent_long,0,1);
-               break;
-
-       case PTRACE_SYSCALL:    /* continue and stop at next (return from) syscall */
-       case PTRACE_CONT:        /* restart after signal. */
-               ret = -EIO;
+       switch (request) {
+       /* First the common request for 31/64 bit */
+       case PTRACE_SYSCALL:
+               /* continue and stop at next (return from) syscall */
+       case PTRACE_CONT:
+               /* restart after signal. */
                if ((unsigned long) data >= _NSIG)
-                       break;
+                       return -EIO;
                if (request == PTRACE_SYSCALL)
                        set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
                else
@@ -525,86 +507,104 @@
                /* make sure the single step bit is not set. */
                clear_single_step(child);
                wake_up_process(child);
-               ret = 0;
-               break;
+               return 0;

-/*
- * make the child exit.  Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
        case PTRACE_KILL:
-               ret = 0;
+               /*
+                * make the child exit.  Best I can do is send it a sigkill.
+                * perhaps it should be put in the status that it wants to
+                * exit.
+                */
                if (child->state == TASK_ZOMBIE) /* already dead */
-                       break;
+                       return 0;
                child->exit_code = SIGKILL;
+               /* make sure the single step bit is not set. */
                clear_single_step(child);
                wake_up_process(child);
-               /* make sure the single step bit is not set. */
-               break;
+               return 0;

-       case PTRACE_SINGLESTEP:  /* set the trap flag. */
-               ret = -EIO;
+       case PTRACE_SINGLESTEP:
+               /* set the trap flag. */
                if ((unsigned long) data >= _NSIG)
-                       break;
+                       return -EIO;
                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
                child->exit_code = data;
                set_single_step(child);
                /* give it a chance to run. */
                wake_up_process(child);
-               ret = 0;
-               break;
+               return 0;

-       case PTRACE_DETACH:  /* detach a process that was attached. */
-               ret = ptrace_detach(child, data);
-               break;
+       case PTRACE_DETACH:
+               /* detach a process that was attached. */
+               return ptrace_detach(child, data);

-       case PTRACE_PEEKUSR_AREA:
-       case PTRACE_POKEUSR_AREA:
-               if(parent_31bit)
-               {
-                       ptrace_area_emu31   parea;
-                       if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
-                               ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-                                             parea.len,1,(request==PTRACE_POKEUSR_AREA));
-               }
-               else
-               {
-                       ptrace_area   parea;
-                       if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
-                               ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-                                             parea.len,1,(request==PTRACE_POKEUSR_AREA));
-               }
-               break;
-       case PTRACE_SETOPTIONS: {
+       case PTRACE_SETOPTIONS:
                if (data & PTRACE_O_TRACESYSGOOD)
                        child->ptrace |= PT_TRACESYSGOOD;
                else
                        child->ptrace &= ~PT_TRACESYSGOOD;
-               ret = 0;
-               break;
-       }
+               return 0;
+       /* Do requests that differ for 31/64 bit */
        default:
-               ret = -EIO;
-               break;
+#ifdef CONFIG_S390_SUPPORT
+               if (current->thread.flags & S390_FLAG_31BIT)
+                       return do_ptrace_emu31(child, request, addr, data);
+#endif
+               return do_ptrace_normal(child, request, addr, data);
+              
        }
- out_tsk:
+       return -EIO;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+       struct task_struct *child;
+       int ret;
+
+       lock_kernel();
+
+       if (request == PTRACE_TRACEME) {
+               /* are we already being traced? */
+               ret = -EPERM;
+               if (current->ptrace & PT_PTRACED)
+                       goto out;
+               ret = security_ops->ptrace(current->parent, current);
+               if (ret)
+                       goto out;
+               /* set the ptrace bit in the process flags. */
+               current->ptrace |= PT_PTRACED;
+               goto out;
+       }
+
+       ret = -EPERM;
+       if (pid == 1)           /* you may not mess with init */
+               goto out;
+
+       ret = -ESRCH;
+       read_lock(&tasklist_lock);
+       child = find_task_by_pid(pid);
+       if (child)
+               get_task_struct(child);
+       read_unlock(&tasklist_lock);
+       if (!child)
+               goto out;
+
+       ret = do_ptrace(child, request, addr, data);
+
        put_task_struct(child);
- out:
+out:
        unlock_kernel();
        return ret;
 }

-
-
 asmlinkage void syscall_trace(void)
 {
        if (!test_thread_flag(TIF_SYSCALL_TRACE))
                return;
        if (!(current->ptrace & PT_PTRACED))
                return;
-       current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-                                       ? 0x80 : 0);
+       current->exit_code =
+               SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0);
        current->state = TASK_STOPPED;
        notify_parent(current, SIGCHLD);
        schedule();
diff -urN linux-2.5.39/arch/s390x/kernel/ptrace32.h linux-2.5.39-s390/arch/s390x/kernel/ptrace32.h
--- linux-2.5.39/arch/s390x/kernel/ptrace32.h   Thu Jan  1 01:00:00 1970
+++ linux-2.5.39-s390/arch/s390x/kernel/ptrace32.h      Mon Sep 30 13:33:16 2002
@@ -0,0 +1,86 @@
+#ifndef _PTRACE32_H
+#define _PTRACE32_H
+
+#include "linux32.h"  /* needed for _psw_t32 */
+
+typedef struct
+{
+       __u32 cr[3];
+} per_cr_words32  __attribute__((packed));
+
+typedef struct
+{
+       __u16          perc_atmid;          /* 0x096 */
+       __u32          address;             /* 0x098 */
+       __u8           access_id;           /* 0x0a1 */
+} per_lowcore_words32  __attribute__((packed));
+
+typedef struct
+{
+       union {
+               per_cr_words32   words;
+       } control_regs  __attribute__((packed));
+       /*
+        * Use these flags instead of setting em_instruction_fetch
+        * directly they are used so that single stepping can be
+        * switched on & off while not affecting other tracing
+        */
+       unsigned  single_step       : 1;
+       unsigned  instruction_fetch : 1;
+       unsigned                    : 30;
+       /*
+        * These addresses are copied into cr10 & cr11 if single
+        * stepping is switched off
+        */
+       __u32     starting_addr;
+       __u32     ending_addr;
+       union {
+               per_lowcore_words32 words;
+       } lowcore;
+} per_struct32 __attribute__((packed));
+
+struct user_regs_struct32
+{
+       _psw_t32 psw;
+       u32 gprs[NUM_GPRS];
+       u32 acrs[NUM_ACRS];
+       u32 orig_gpr2;
+       s390_fp_regs fp_regs;
+       /*
+        * These per registers are in here so that gdb can modify them
+        * itself as there is no "official" ptrace interface for hardware
+        * watchpoints. This is the way intel does it.
+        */
+       per_struct32 per_info;
+       u32  ieee_instruction_pointer;
+       /* Used to give failing instruction back to user for ieee exceptions */
+};
+
+struct user32 {
+       /* We start with the registers, to mimic the way that "memory"
+          is returned from the ptrace(3,...) function.  */
+       struct user_regs_struct32 regs; /* Where the registers are actually stored */
+       /* The rest of this junk is to help gdb figure out what goes where */
+       u32 u_tsize;            /* Text segment size (pages). */
+       u32 u_dsize;            /* Data segment size (pages). */
+       u32 u_ssize;            /* Stack segment size (pages). */
+       u32 start_code;         /* Starting virtual address of text. */
+       u32 start_stack;        /* Starting virtual address of stack area.
+                                  This is actually the bottom of the stack,
+                                  the top of the stack is always found in the
+                                  esp register.  */
+       s32 signal;              /* Signal that caused the core dump. */
+       u32 u_ar0;               /* Used by gdb to help find the values for */
+                                /* the registers. */
+       u32 magic;               /* To uniquely identify a core file */
+       char u_comm[32];         /* User command that was responsible */
+};
+
+typedef struct
+{
+       __u32   len;
+       __u32   kernel_addr;
+       __u32   process_addr;
+} ptrace_area_emu31;
+
+#endif /* _PTRACE32_H */
diff -urN linux-2.5.39/arch/s390x/kernel/setup.c linux-2.5.39-s390/arch/s390x/kernel/setup.c
--- linux-2.5.39/arch/s390x/kernel/setup.c      Mon Sep 30 13:33:09 2002
+++ linux-2.5.39-s390/arch/s390x/kernel/setup.c Mon Sep 30 13:33:16 2002
@@ -304,7 +304,7 @@
        unsigned long start_pfn, end_pfn;
         static unsigned int smptrap=0;
         unsigned long delay = 0;
-       struct _lowcore *lowcore;
+       struct _lowcore *lc;
        int i;

         if (smptrap)
@@ -441,27 +441,30 @@
         /*
          * Setup lowcore for boot cpu
          */
-       lowcore = (struct _lowcore *)
-               __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0);
-       memset(lowcore, 0, 2*PAGE_SIZE);
-       lowcore->restart_psw.mask = _RESTART_PSW_MASK;
-       lowcore->restart_psw.addr = (addr_t) &restart_int_handler;
-       lowcore->external_new_psw.mask = _EXT_PSW_MASK;
-       lowcore->external_new_psw.addr = (addr_t) &ext_int_handler;
-       lowcore->svc_new_psw.mask = _SVC_PSW_MASK;
-       lowcore->svc_new_psw.addr = (addr_t) &system_call;
-       lowcore->program_new_psw.mask = _PGM_PSW_MASK;
-       lowcore->program_new_psw.addr = (addr_t) &pgm_check_handler;
-       lowcore->mcck_new_psw.mask = _MCCK_PSW_MASK;
-       lowcore->mcck_new_psw.addr = (addr_t) &mcck_int_handler;
-       lowcore->io_new_psw.mask = _IO_PSW_MASK;
-       lowcore->io_new_psw.addr = (addr_t) &io_int_handler;
-       lowcore->ipl_device = S390_lowcore.ipl_device;
-       lowcore->kernel_stack = ((__u64) &init_thread_union) + 16384;
-       lowcore->async_stack = (__u64)
+       lc = (struct _lowcore *) __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0);
+       memset(lc, 0, 2*PAGE_SIZE);
+       lc->restart_psw.mask = PSW_BASE_BITS;
+       lc->restart_psw.addr = (addr_t) &restart_int_handler;
+       lc->external_new_psw.mask = PSW_KERNEL_BITS;
+       lc->external_new_psw.addr = (addr_t) &ext_int_handler;
+       lc->svc_new_psw.mask = PSW_KERNEL_BITS;
+       lc->svc_new_psw.addr = (addr_t) &system_call;
+       lc->program_new_psw.mask = PSW_KERNEL_BITS;
+       lc->program_new_psw.addr = (addr_t) &pgm_check_handler;
+       lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
+       lc->mcck_new_psw.addr = (addr_t) &mcck_int_handler;
+       lc->io_new_psw.mask = PSW_KERNEL_BITS;
+       lc->io_new_psw.addr = (addr_t) &io_int_handler;
+       lc->ipl_device = S390_lowcore.ipl_device;
+       lc->kernel_stack = ((__u64) &init_thread_union) + 16384;
+       lc->async_stack = (__u64)
                __alloc_bootmem(4*PAGE_SIZE, 4*PAGE_SIZE, 0) + 16384;
-       lowcore->jiffy_timer = -1LL;
-       set_prefix((__u32)(__u64) lowcore);
+       lc->jiffy_timer = -1LL;
+       if (MACHINE_HAS_DIAG44)
+               lc->diag44_opcode = 0x83000044;
+       else
+               lc->diag44_opcode = 0x07000700;
+       set_prefix((__u32)(__u64) lc);
         cpu_init();
         __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;

diff -urN linux-2.5.39/arch/s390x/kernel/signal.c linux-2.5.39-s390/arch/s390x/kernel/signal.c
--- linux-2.5.39/arch/s390x/kernel/signal.c     Mon Sep 30 13:33:16 2002
+++ linux-2.5.39-s390/arch/s390x/kernel/signal.c        Mon Sep 30 13:33:16 2002
@@ -162,7 +162,7 @@
        int err;

        err = __copy_from_user(regs, &sregs->regs, sizeof(_s390_regs_common));
-       regs->psw.mask = _USER_PSW_MASK | (regs->psw.mask & PSW_MASK_DEBUGCHANGE);
+       regs->psw.mask = PSW_USER_BITS | (regs->psw.mask & PSW_MASK_CC);
        if (err)
                return err;

@@ -292,9 +292,9 @@
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ka->sa.sa_flags & SA_RESTORER) {
-                regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+                regs->gprs[14] = (__u64) ka->sa.sa_restorer;
        } else {
-                regs->gprs[14] = FIX_PSW(frame->retcode);
+                regs->gprs[14] = (__u64) frame->retcode;
                if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
                               (u16 *)(frame->retcode)))
                        goto give_sigsegv;
@@ -305,12 +305,12 @@
                goto give_sigsegv;

        /* Set up registers for signal handler */
-       regs->gprs[15] = (addr_t)frame;
-       regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
-       regs->psw.mask = _USER_PSW_MASK;
+       regs->gprs[15] = (__u64) frame;
+       regs->psw.addr = (__u64) ka->sa.sa_handler;
+       regs->psw.mask = PSW_USER_BITS;

        regs->gprs[2] = map_signal(sig);
-       regs->gprs[3] = (addr_t)&frame->sc;
+       regs->gprs[3] = (__u64) &frame->sc;

        /* We forgot to include these in the sigcontext.
           To avoid breaking binary compatibility, they are passed as args. */
@@ -350,9 +350,9 @@
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ka->sa.sa_flags & SA_RESTORER) {
-                regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+                regs->gprs[14] = (__u64) ka->sa.sa_restorer;
        } else {
-                regs->gprs[14] = FIX_PSW(frame->retcode);
+                regs->gprs[14] = (__u64) frame->retcode;
                err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
                                  (u16 *)(frame->retcode));
        }
@@ -362,13 +362,13 @@
                goto give_sigsegv;

        /* Set up registers for signal handler */
-       regs->gprs[15] = (addr_t)frame;
-       regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
-       regs->psw.mask = _USER_PSW_MASK;
+       regs->gprs[15] = (__u64) frame;
+       regs->psw.addr = (__u64) ka->sa.sa_handler;
+       regs->psw.mask = PSW_USER_BITS;

        regs->gprs[2] = map_signal(sig);
-       regs->gprs[3] = (addr_t)&frame->info;
-       regs->gprs[4] = (addr_t)&frame->uc;
+       regs->gprs[3] = (__u64) &frame->info;
+       regs->gprs[4] = (__u64) &frame->uc;
        return;

 give_sigsegv:
diff -urN linux-2.5.39/arch/s390x/kernel/signal32.c linux-2.5.39-s390/arch/s390x/kernel/signal32.c
--- linux-2.5.39/arch/s390x/kernel/signal32.c   Mon Sep 30 13:33:16 2002
+++ linux-2.5.39-s390/arch/s390x/kernel/signal32.c      Mon Sep 30 13:33:16 2002
@@ -29,15 +29,10 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include "linux32.h"
+#include "ptrace32.h"

 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))

-#define _ADDR_31 0x80000000
-#define _USER_PSW_MASK_EMU32 0x070DC000
-#define _USER_PSW_MASK32 0x0705C00080000000
-#define PSW_MASK_DEBUGCHANGE32 0x00003000UL
-#define PSW_ADDR_DEBUGCHANGE32 0x7FFFFFFFUL
-
 typedef struct
 {
        __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
@@ -297,9 +292,9 @@
        _s390_regs_common32 regs32;
        int err, i;

-       regs32.psw.mask = _USER_PSW_MASK_EMU32 |
-               (__u32)((regs->psw.mask & PSW_MASK_DEBUGCHANGE) >> 32);
-       regs32.psw.addr = _ADDR_31 | (__u32) regs->psw.addr;
+       regs32.psw.mask = PSW32_USER_BITS |
+               ((__u32)(regs->psw.mask >> 32) & PSW32_MASK_CC);
+       regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
        for (i = 0; i < NUM_GPRS; i++)
                regs32.gprs[i] = (__u32) regs->gprs[i];
        memcpy(regs32.acrs, regs->acrs, sizeof(regs32.acrs));
@@ -320,9 +315,9 @@
        err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
        if (err)
                return err;
-       regs->psw.mask = _USER_PSW_MASK32 |
-               (__u64)(regs32.psw.mask & PSW_MASK_DEBUGCHANGE32) << 32;
-       regs->psw.addr = (__u64)(regs32.psw.addr & PSW_ADDR_DEBUGCHANGE32);
+       regs->psw.mask = PSW_USER32_BITS |
+               (__u64)(regs32.psw.mask & PSW32_MASK_CC) << 32;
+       regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
        for (i = 0; i < NUM_GPRS; i++)
                regs->gprs[i] = (__u64) regs32.gprs[i];
        memcpy(regs->acrs, regs32.acrs, sizeof(regs32.acrs));
@@ -467,9 +462,9 @@
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ka->sa.sa_flags & SA_RESTORER) {
-               regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+               regs->gprs[14] = (__u64) ka->sa.sa_restorer;
        } else {
-               regs->gprs[14] = FIX_PSW(frame->retcode);
+               regs->gprs[14] = (__u64) frame->retcode;
                if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
                               (u16 *)(frame->retcode)))
                        goto give_sigsegv;
@@ -480,12 +475,12 @@
                goto give_sigsegv;

        /* Set up registers for signal handler */
-       regs->gprs[15] = (addr_t)frame;
-       regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
-       regs->psw.mask = _USER_PSW_MASK32;
+       regs->gprs[15] = (__u64) frame;
+       regs->psw.addr = (__u64) ka->sa.sa_handler;
+       regs->psw.mask = PSW_USER32_BITS;

        regs->gprs[2] = map_signal(sig);
-       regs->gprs[3] = (addr_t)&frame->sc;
+       regs->gprs[3] = (__u64) &frame->sc;

        /* We forgot to include these in the sigcontext.
           To avoid breaking binary compatibility, they are passed as args. */
@@ -525,9 +520,9 @@
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ka->sa.sa_flags & SA_RESTORER) {
-               regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+               regs->gprs[14] = (__u64) ka->sa.sa_restorer;
        } else {
-               regs->gprs[14] = FIX_PSW(frame->retcode);
+               regs->gprs[14] = (__u64) frame->retcode;
                err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
                                  (u16 *)(frame->retcode));
        }
@@ -537,13 +532,13 @@
                goto give_sigsegv;

        /* Set up registers for signal handler */
-       regs->gprs[15] = (addr_t)frame;
-       regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
-       regs->psw.mask = _USER_PSW_MASK32;
+       regs->gprs[15] = (__u64) frame;
+       regs->psw.addr = (__u64) ka->sa.sa_handler;
+       regs->psw.mask = PSW_USER32_BITS;

        regs->gprs[2] = map_signal(sig);
-       regs->gprs[3] = (addr_t)&frame->info;
-       regs->gprs[4] = (addr_t)&frame->uc;
+       regs->gprs[3] = (__u64) &frame->info;
+       regs->gprs[4] = (__u64) &frame->uc;
        return;

 give_sigsegv:
diff -urN linux-2.5.39/arch/s390x/kernel/traps.c linux-2.5.39-s390/arch/s390x/kernel/traps.c
--- linux-2.5.39/arch/s390x/kernel/traps.c      Mon Sep 30 13:25:21 2002
+++ linux-2.5.39-s390/arch/s390x/kernel/traps.c Mon Sep 30 13:33:16 2002
@@ -118,22 +118,22 @@
                stack = (unsigned long*)&stack;

        printk("Call Trace: ");
-       low_addr = ((unsigned long) stack) & PSW_ADDR_MASK;
+       low_addr = (unsigned long) stack;
        high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
        /* Skip the first frame (biased stack) */
-       backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK;
+       backchain = *(unsigned long *) low_addr;
        /* Print up to 8 lines */
        for (i = 0; i < 8; i++) {
                if (backchain < low_addr || backchain >= high_addr)
                        break;
-               ret_addr = *((unsigned long *) (backchain+112)) & PSW_ADDR_MASK;
+               ret_addr = *(unsigned long *) (backchain+112);
                if (!kernel_text_address(ret_addr))
                        break;
                if (i && ((i % 3) == 0))
                        printk("\n   ");
                printk("[<%016lx>] ", ret_addr);
                low_addr = backchain;
-               backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK;
+               backchain = *(unsigned long *) backchain;
        }
        printk("\n");
 }
@@ -186,7 +186,7 @@
        char *mode;
        int i;

-       mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl";
+       mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
        printk("%s PSW : %016lx %016lx\n",
               mode, (unsigned long) regs->psw.mask,
               (unsigned long) regs->psw.addr);
@@ -212,7 +212,7 @@
         * time of the fault.
         */
        old_fs = get_fs();
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                set_fs(USER_DS);
        else
                set_fs(KERNEL_DS);
@@ -289,10 +289,10 @@
         * We got all needed information from the lowcore and can
         * now safely switch on interrupts.
         */
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();

-        if (regs->psw.mask & PSW_PROBLEM_STATE) {
+        if (regs->psw.mask & PSW_MASK_PSTATE) {
                 struct task_struct *tsk = current;
                 tsk->thread.trap_no = interruption_code & 0xffff;
                if (info)
@@ -323,12 +323,12 @@

 static inline void *get_check_address(struct pt_regs *regs)
 {
-       return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
+       return (void *)(regs->psw.addr - S390_lowcore.pgm_ilc);
 }

 int do_debugger_trap(struct pt_regs *regs,int signal)
 {
-       if(regs->psw.mask&PSW_PROBLEM_STATE)
+       if(regs->psw.mask&PSW_MASK_PSTATE)
        {
                if(current->ptrace & PT_PTRACED)
                        force_sig(signal,current);
@@ -426,14 +426,14 @@
         * We got all needed information from the lowcore and can
         * now safely switch on interrupts.
         */
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();

        /* WARNING don't change this check back to */
-       /* int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); */
+       /* int problem_state=(regs->psw.mask & PSW_MASK_PSTATE); */
        /* & then doing if(problem_state) an int is too small for this */
        /* check on 64 bit. */
-       if(regs->psw.mask & PSW_PROBLEM_STATE)
+       if(regs->psw.mask & PSW_MASK_PSTATE)
                get_user(*((__u16 *) opcode), location);
        else
                *((__u16 *)opcode)=*((__u16 *)location);
@@ -459,7 +459,7 @@
         * We got all needed information from the lowcore and can
         * now safely switch on interrupts.
         */
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();

        __asm__ volatile ("stfpc %0\n\t"
@@ -527,21 +527,19 @@

 void handle_per_exception(struct pt_regs *regs)
 {
-       if(regs->psw.mask&PSW_PROBLEM_STATE)
-       {
+       if (regs->psw.mask&PSW_MASK_PSTATE) {
                per_struct *per_info=&current->thread.per_info;
                per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
                per_info->lowcore.words.address=S390_lowcore.per_address;
                per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
        }
-       if(do_debugger_trap(regs,SIGTRAP))
-       {
+       if (do_debugger_trap(regs,SIGTRAP)) {
                /* I've seen this possibly a task structure being reused ? */
                printk("Spurious per exception detected\n");
                printk("switching off per tracing for this task.\n");
                show_regs(regs);
                /* Hopefully switching off per tracing will help us survive */
-               regs->psw.mask &= ~PSW_PER_MASK;
+               regs->psw.mask &= ~PSW_MASK_PER;
        }
 }

diff -urN linux-2.5.39/arch/s390x/mm/fault.c linux-2.5.39-s390/arch/s390x/mm/fault.c
--- linux-2.5.39/arch/s390x/mm/fault.c  Mon Sep 30 13:33:09 2002
+++ linux-2.5.39-s390/arch/s390x/mm/fault.c     Mon Sep 30 13:33:16 2002
@@ -167,7 +167,7 @@

                /* Low-address protection hit in kernel mode means
                   NULL pointer write access in kernel mode.  */
-               if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
+               if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
                        address = 0;
                        user_address = 0;
                        goto no_context;
@@ -259,7 +259,7 @@
         up_read(&mm->mmap_sem);

         /* User mode accesses just cause a SIGSEGV */
-        if (regs->psw.mask & PSW_PROBLEM_STATE) {
+        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);
@@ -299,7 +299,7 @@
                goto survive;
        }
        printk("VM: killing process %s\n", tsk->comm);
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                do_exit(SIGKILL);
        goto no_context;

@@ -315,7 +315,7 @@
        force_sig(SIGBUS, tsk);

        /* Kernel mode? Handle exceptions or die */
-       if (!(regs->psw.mask & PSW_PROBLEM_STATE))
+       if (!(regs->psw.mask & PSW_MASK_PSTATE))
                goto no_context;
 }

@@ -441,7 +441,7 @@
         * We got all needed information from the lowcore and can
         * now safely switch on interrupts.
         */
-       if (regs->psw.mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_MASK_PSTATE)
                local_irq_enable();

        if (subcode & 0x0080) {
diff -urN linux-2.5.39/drivers/s390/cio/cio.c linux-2.5.39-s390/drivers/s390/cio/cio.c
--- linux-2.5.39/drivers/s390/cio/cio.c Mon Sep 30 13:33:09 2002
+++ linux-2.5.39-s390/drivers/s390/cio/cio.c    Mon Sep 30 13:33:16 2002
@@ -98,7 +98,6 @@
 s390_do_sync_wait(int irq, int do_tpi)
 {
        unsigned long psw_mask;
-       int ccode;
        uint64_t time_start;
        uint64_t time_curr;

@@ -116,31 +115,7 @@
         *  sync. interrupt arrived we reset the I/O old PSW to
         *  its original value.
         */
-      
-       ccode = iac ();
-      
-       switch (ccode) {
-       case 0: /* primary-space */
-               psw_mask = _IO_PSW_MASK
-                       | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
-               break;
-       case 1: /* secondary-space */
-               psw_mask = _IO_PSW_MASK
-                       | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
-               break;
-       case 2: /* access-register */
-               psw_mask = _IO_PSW_MASK
-                       | _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
-               break;
-       case 3: /* home-space */
-               psw_mask = _IO_PSW_MASK
-                       | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
-               break;
-       default:
-               panic ("start_IO() : unexpected "
-                      "address-space-control %d\n", ccode);
-               break;
-       }
+       psw_mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_WAIT;

        /*
         * Martin didn't like modifying the new PSW, now we take
@@ -201,7 +176,6 @@
        int io_sub;
        __u32 io_parm;
        unsigned long psw_mask;
-       int ccode;

        int ready = 0;

@@ -212,32 +186,7 @@
         * FIXME: Are there case where we can't rely on an interrupt
         *        to occurr? Need to check...
         */
-
-       ccode = iac ();
-      
-       switch (ccode) {
-       case 0: /* primary-space */
-               psw_mask = _IO_PSW_MASK
-                       | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
-               break;
-       case 1: /* secondary-space */
-               psw_mask = _IO_PSW_MASK
-                       | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
-               break;
-       case 2: /* access-register */
-               psw_mask = _IO_PSW_MASK
-                       | _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
-               break;
-       case 3: /* home-space */
-               psw_mask = _IO_PSW_MASK
-                       | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
-               break;
-       default: /* FIXME: isn't ccode only 2 bits anyway? */
-               panic (halt?"halt":"clear"
-                      "_IO() : unexpected address-space-control %d\n",
-                      ccode);
-               break;
-       }
+       psw_mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_WAIT;

        /*
         * Martin didn't like modifying the new PSW, now we take
@@ -960,7 +909,7 @@
         *       entry condition to synchronous I/O.
         */
        if (*(__u32 *) __LC_SYNC_IO_WORD) {
-               regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
+               regs.psw.mask &= ~(PSW_MASK_WAIT | PSW_MASK_IO);
                return;
        }
        /* endif */
diff -urN linux-2.5.39/include/asm-s390/lowcore.h linux-2.5.39-s390/include/asm-s390/lowcore.h
--- linux-2.5.39/include/asm-s390/lowcore.h     Mon Sep 30 13:33:09 2002
+++ linux-2.5.39-s390/include/asm-s390/lowcore.h        Mon Sep 30 13:33:16 2002
@@ -52,41 +52,12 @@

 #define __LC_PFAULT_INTPARM             0x080

-/* interrupt handler start with all io, external and mcck interrupt disabled */
-
-#define _RESTART_PSW_MASK    0x00080000
-#define _EXT_PSW_MASK        0x04080000
-#define _PGM_PSW_MASK        0x04080000
-#define _SVC_PSW_MASK        0x04080000
-#define _MCCK_PSW_MASK       0x04080000
-#define _IO_PSW_MASK         0x04080000
-#define _USER_PSW_MASK       0x070DC000/* DAT, IO, EXT, Home-space         */
-#define _WAIT_PSW_MASK       0x070E0000/* DAT, IO, EXT, Wait, Home-space   */
-#define _DW_PSW_MASK         0x000A0000/* disabled wait PSW mask           */
-
-#define _PRIMARY_MASK        0x0000    /* MASK for SACF                    */
-#define _SECONDARY_MASK      0x0100    /* MASK for SACF                    */
-#define _ACCESS_MASK         0x0200    /* MASK for SACF                    */
-#define _HOME_MASK           0x0300    /* MASK for SACF                    */
-
-#define _PSW_PRIM_SPACE_MODE 0x00000000
-#define _PSW_SEC_SPACE_MODE  0x00008000
-#define _PSW_ACC_REG_MODE    0x00004000
-#define _PSW_HOME_SPACE_MODE 0x0000C000
-
-#define _PSW_WAIT_MASK_BIT   0x00020000 /* Wait bit */
-#define _PSW_IO_MASK_BIT     0x02000000 /* IO bit */
-#define _PSW_IO_WAIT         0x02020000 /* IO & Wait bit */
-
-/* we run in 31 Bit mode */
-#define _ADDR_31             0x80000000
-
 #ifndef __ASSEMBLY__

 #include <linux/config.h>
-#include <asm/processor.h>
 #include <linux/types.h>
 #include <asm/atomic.h>
+#include <asm/processor.h>
 #include <asm/sigp.h>

 void restart_int_handler(void);
diff -urN linux-2.5.39/include/asm-s390/processor.h linux-2.5.39-s390/include/asm-s390/processor.h
--- linux-2.5.39/include/asm-s390/processor.h   Fri Sep 27 23:49:53 2002
+++ linux-2.5.39-s390/include/asm-s390/processor.h      Mon Sep 30 13:33:16 2002
@@ -101,8 +101,8 @@

 /* need to define ... */
 #define start_thread(regs, new_psw, new_stackp) do {            \
-        regs->psw.mask  = _USER_PSW_MASK;                       \
-        regs->psw.addr  = new_psw | 0x80000000;                 \
+        regs->psw.mask  = PSW_USER_BITS;                        \
+        regs->psw.addr  = new_psw | PSW_ADDR_AMODE31;           \
         regs->gprs[15]  = new_stackp ;                          \
 } while (0)

@@ -137,19 +137,6 @@
 #define cpu_relax()    barrier()

 /*
- * Set of msr bits that gdb can change on behalf of a process.
- */
-/* Only let our hackers near the condition codes */
-#define PSW_MASK_DEBUGCHANGE    0x00003000UL
-/* Don't let em near the addressing mode either */    
-#define PSW_ADDR_DEBUGCHANGE    0x7FFFFFFFUL
-#define PSW_ADDR_MASK           0x7FFFFFFFUL
-/* Program event recording mask */    
-#define PSW_PER_MASK            0x40000000UL
-#define USER_STD_MASK           0x00000080UL
-#define PSW_PROBLEM_STATE       0x00010000UL
-
-/*
  * Set PSW mask to specified value, while leaving the
  * PSW addr pointing to the next instruction.
  */
@@ -178,7 +165,8 @@
        unsigned long reg;
        psw_t wait_psw;

-       wait_psw.mask = 0x070e0000;
+       wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
+               PSW_MASK_MCHECK | PSW_MASK_WAIT;
        asm volatile (
                "    basr %0,0\n"
                "0:  la   %0,1f-0b(%0)\n"
@@ -200,7 +188,7 @@
         psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
                                   & -sizeof(psw_t));

-        dw_psw->mask = 0x000a0000;
+        dw_psw->mask = PSW_BASE_BITS | PSW_MASK_WAIT;
         dw_psw->addr = code;
         /*
          * Store status and then load disabled wait psw,
diff -urN linux-2.5.39/include/asm-s390/ptrace.h linux-2.5.39-s390/include/asm-s390/ptrace.h
--- linux-2.5.39/include/asm-s390/ptrace.h      Fri Sep 27 23:49:10 2002
+++ linux-2.5.39-s390/include/asm-s390/ptrace.h Mon Sep 30 13:33:16 2002
@@ -114,7 +114,6 @@
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
-
 #include <asm/setup.h>

 /* this typedef defines how a Program Status Word looks like */
@@ -124,10 +123,32 @@
         __u32   addr;
 } __attribute__ ((aligned(8))) psw_t;

-#ifdef __KERNEL__
-#define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL)
-#define ADDR_BITS_REMOVE(addr) ((addr)&0x7fffffff)
-#endif
+#define PSW_MASK_PER           0x40000000UL
+#define PSW_MASK_DAT           0x04000000UL
+#define PSW_MASK_IO            0x02000000UL
+#define PSW_MASK_EXT           0x01000000UL
+#define PSW_MASK_KEY           0x00F00000UL
+#define PSW_MASK_MCHECK                0x00040000UL
+#define PSW_MASK_WAIT          0x00020000UL
+#define PSW_MASK_PSTATE                0x00010000UL
+#define PSW_MASK_ASC           0x0000C000UL
+#define PSW_MASK_CC            0x00003000UL
+#define PSW_MASK_PM            0x00000F00UL
+
+#define PSW_ADDR_AMODE31       0x80000000UL
+#define PSW_ADDR_INSN          0x7FFFFFFFUL
+
+#define PSW_BASE_BITS          0x00080000UL
+
+#define PSW_ASC_PRIMARY                0x00000000UL
+#define PSW_ASC_ACCREG         0x00004000UL
+#define PSW_ASC_SECONDARY      0x00008000UL
+#define PSW_ASC_HOME           0x0000C000UL
+
+#define PSW_KERNEL_BITS        (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY)
+#define PSW_USER_BITS  (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
+                        PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
+                        PSW_MASK_PSTATE)

 typedef union
 {
@@ -328,8 +349,8 @@
 };

 #ifdef __KERNEL__
-#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0)
-#define instruction_pointer(regs) ((regs)->psw.addr)
+#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
+#define instruction_pointer(regs) ((regs)->psw.addr & PSW_MASK_INSN)
 extern void show_regs(struct pt_regs * regs);
 #endif

diff -urN linux-2.5.39/include/asm-s390x/lowcore.h linux-2.5.39-s390/include/asm-s390x/lowcore.h
--- linux-2.5.39/include/asm-s390x/lowcore.h    Mon Sep 30 13:33:09 2002
+++ linux-2.5.39-s390/include/asm-s390x/lowcore.h       Mon Sep 30 13:33:16 2002
@@ -56,32 +56,6 @@

 #define __LC_PFAULT_INTPARM             0x11B8

-/* interrupt handler start with all io, external and mcck interrupt disabled */
-
-#define _RESTART_PSW_MASK    0x0000000180000000
-#define _EXT_PSW_MASK        0x0400000180000000
-#define _PGM_PSW_MASK        0x0400000180000000
-#define _SVC_PSW_MASK        0x0400000180000000
-#define _MCCK_PSW_MASK       0x0400000180000000
-#define _IO_PSW_MASK         0x0400000180000000
-#define _USER_PSW_MASK       0x0705C00180000000
-#define _WAIT_PSW_MASK       0x0706000180000000
-#define _DW_PSW_MASK         0x0002000180000000
-
-#define _PRIMARY_MASK        0x0000    /* MASK for SACF                    */
-#define _SECONDARY_MASK      0x0100    /* MASK for SACF                    */
-#define _ACCESS_MASK         0x0200    /* MASK for SACF                    */
-#define _HOME_MASK           0x0300    /* MASK for SACF                    */
-
-#define _PSW_PRIM_SPACE_MODE 0x0000000000000000
-#define _PSW_SEC_SPACE_MODE  0x0000800000000000
-#define _PSW_ACC_REG_MODE    0x0000400000000000
-#define _PSW_HOME_SPACE_MODE 0x0000C00000000000
-
-#define _PSW_WAIT_MASK_BIT   0x0002000000000000
-#define _PSW_IO_MASK_BIT     0x0200000000000000
-#define _PSW_IO_WAIT         0x0202000000000000
-
 #ifndef __ASSEMBLY__

 #include <linux/config.h>
diff -urN linux-2.5.39/include/asm-s390x/processor.h linux-2.5.39-s390/include/asm-s390x/processor.h
--- linux-2.5.39/include/asm-s390x/processor.h  Fri Sep 27 23:49:17 2002
+++ linux-2.5.39-s390/include/asm-s390x/processor.h     Mon Sep 30 13:33:16 2002
@@ -111,13 +111,13 @@

 /* need to define ... */
 #define start_thread(regs, new_psw, new_stackp) do {            \
-        regs->psw.mask  = _USER_PSW_MASK;                       \
+        regs->psw.mask  = PSW_USER_BITS;                        \
         regs->psw.addr  = new_psw;                              \
         regs->gprs[15]  = new_stackp;                           \
 } while (0)

 #define start_thread31(regs, new_psw, new_stackp) do {          \
-       regs->psw.mask  = _USER_PSW_MASK & ~(1L << 32);            \
+       regs->psw.mask  = PSW_USER32_BITS;                   \
         regs->psw.addr  = new_psw;                              \
         regs->gprs[15]  = new_stackp;                           \
 } while (0)
@@ -154,19 +154,6 @@
 #define cpu_relax()    barrier()

 /*
- * Set of msr bits that gdb can change on behalf of a process.
- */
-/* Only let our hackers near the condition codes */
-#define PSW_MASK_DEBUGCHANGE    0x0000300000000000UL
-/* Don't let em near the addressing mode either */    
-#define PSW_ADDR_DEBUGCHANGE    0xFFFFFFFFFFFFFFFFUL
-#define PSW_ADDR_MASK           0xFFFFFFFFFFFFFFFFUL
-/* Program event recording mask */    
-#define PSW_PER_MASK            0x4000000000000000UL
-#define USER_STD_MASK           0x0000000000000080UL
-#define PSW_PROBLEM_STATE       0x0001000000000000UL
-
-/*
  * Set PSW mask to specified value, while leaving the
  * PSW addr pointing to the next instruction.
  */
@@ -194,7 +181,8 @@
        unsigned long reg;
        psw_t wait_psw;

-       wait_psw.mask = 0x0706000180000000;
+       wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
+               PSW_MASK_MCHECK | PSW_MASK_WAIT;
        asm volatile (
                "    larl  %0,0f\n"
                "    stg   %0,8(%1)\n"
@@ -214,7 +202,7 @@
         psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
                                   & -sizeof(psw_t));

-        dw_psw->mask = 0x0002000180000000;
+        dw_psw->mask = PSW_BASE_BITS | PSW_MASK_WAIT;
         dw_psw->addr = code;
         /*
          * Store status and then load disabled wait psw,
diff -urN linux-2.5.39/include/asm-s390x/ptrace.h linux-2.5.39-s390/include/asm-s390x/ptrace.h
--- linux-2.5.39/include/asm-s390x/ptrace.h     Fri Sep 27 23:49:14 2002
+++ linux-2.5.39-s390/include/asm-s390x/ptrace.h        Mon Sep 30 13:33:16 2002
@@ -104,10 +104,33 @@
         __u64   addr;
 } __attribute__ ((aligned(8))) psw_t;

-#ifdef __KERNEL__
-#define FIX_PSW(addr) ((unsigned long)(addr))
-#define ADDR_BITS_REMOVE(addr) ((addr))
-#endif
+#define PSW_MASK_PER           0x4000000000000000UL
+#define PSW_MASK_DAT           0x0400000000000000UL
+#define PSW_MASK_IO            0x0200000000000000UL
+#define PSW_MASK_EXT           0x0100000000000000UL
+#define PSW_MASK_KEY           0x00F0000000000000UL
+#define PSW_MASK_MCHECK                0x0004000000000000UL
+#define PSW_MASK_WAIT          0x0002000000000000UL
+#define PSW_MASK_PSTATE                0x0001000000000000UL
+#define PSW_MASK_ASC           0x0000C00000000000UL
+#define PSW_MASK_CC            0x0000300000000000UL
+#define PSW_MASK_PM            0x00000F0000000000UL
+
+#define PSW_BASE_BITS          0x0000000180000000UL
+#define PSW_BASE32_BITS                0x0000000080000000UL
+
+#define PSW_ASC_PRIMARY                0x0000000000000000UL
+#define PSW_ASC_ACCREG         0x0000400000000000UL
+#define PSW_ASC_SECONDARY      0x0000800000000000UL
+#define PSW_ASC_HOME           0x0000C00000000000UL
+
+#define PSW_KERNEL_BITS        (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY)
+#define PSW_USER_BITS  (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
+                        PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
+                        PSW_MASK_PSTATE)
+#define PSW_USER32_BITS (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
+                        PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
+                        PSW_MASK_PSTATE)

 typedef union
 {
@@ -309,7 +332,7 @@
 };

 #ifdef __KERNEL__
-#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0)
+#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
 #define instruction_pointer(regs) ((regs)->psw.addr)
 extern void show_regs(struct pt_regs * regs);
 #endif

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/