]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
[S390] addressing mode limits and psw address wrapping
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 24 Oct 2011 09:47:37 +0000 (11:47 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 24 Oct 2011 09:47:33 +0000 (11:47 +0200)
An instruction with an address right below the adress limit for the
current addressing mode will wrap. The instruction restart logic in
the protection fault handler and the signal code need to follow the
wrapping rules to find the correct instruction address.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/kernel/signal.c
arch/s390/mm/fault.c

index a4b6229e5d4b703f9cf6da874e13f7dc1cc468fb..306c93c1b184a1da69789faaedbc04af857576a5 100644 (file)
@@ -187,7 +187,6 @@ static inline void __load_psw(psw_t psw)
  * Set PSW mask to specified value, while leaving the
  * PSW addr pointing to the next instruction.
  */
-
 static inline void __load_psw_mask (unsigned long mask)
 {
        unsigned long addr;
@@ -212,6 +211,27 @@ static inline void __load_psw_mask (unsigned long mask)
                : "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc");
 #endif /* __s390x__ */
 }
+
+/*
+ * Rewind PSW instruction address by specified number of bytes.
+ */
+static inline unsigned long __rewind_psw(psw_t psw, unsigned long ilc)
+{
+#ifndef __s390x__
+       if (psw.addr & PSW_ADDR_AMODE)
+               /* 31 bit mode */
+               return (psw.addr - ilc) | PSW_ADDR_AMODE;
+       /* 24 bit mode */
+       return (psw.addr - ilc) & ((1UL << 24) - 1);
+#else
+       unsigned long mask;
+
+       mask = (psw.mask & PSW_MASK_EA) ? -1UL :
+              (psw.mask & PSW_MASK_BA) ? (1UL << 31) - 1 :
+                                         (1UL << 24) - 1;
+       return (psw.addr - ilc) & mask;
+#endif
+}
  
 /*
  * Function to stop a processor until an interruption occurred
index 93c907b4776fa08a8bc55aa629bef064cbae3f4b..2904cc66967a69a16f7630659b721982e1967b83 100644 (file)
@@ -236,6 +236,8 @@ typedef struct
 #define PSW_MASK_ASC           0x0000C000UL
 #define PSW_MASK_CC            0x00003000UL
 #define PSW_MASK_PM            0x00000F00UL
+#define PSW_MASK_EA            0x00000000UL
+#define PSW_MASK_BA            0x00000000UL
 
 #define PSW_ADDR_AMODE         0x80000000UL
 #define PSW_ADDR_INSN          0x7FFFFFFFUL
@@ -261,6 +263,8 @@ typedef struct
 #define PSW_MASK_ASC           0x0000C00000000000UL
 #define PSW_MASK_CC            0x0000300000000000UL
 #define PSW_MASK_PM            0x00000F0000000000UL
+#define PSW_MASK_EA            0x0000000100000000UL
+#define PSW_MASK_BA            0x0000000080000000UL
 
 #define PSW_ADDR_AMODE         0x0000000000000000UL
 #define PSW_ADDR_INSN          0xFFFFFFFFFFFFFFFFUL
index e751cab80e04b881f52697f645de3016ff8d5687..058e372bada152904074d8301ff228f945968d7b 100644 (file)
@@ -447,8 +447,9 @@ void do_signal(struct pt_regs *regs)
                        /* fallthrough */
                        case -ERESTARTNOINTR:
                                regs->gprs[2] = regs->orig_gpr2;
-                               regs->psw.addr = regs->psw.addr -
-                                       (regs->svc_code >> 16);
+                               regs->psw.addr =
+                                       __rewind_psw(regs->psw,
+                                                    regs->svc_code >> 16);
                                break;
                        }
                        /* No longer in a system call */
index 9564fc779b27a6071cfe08fac6932aa8e08eb23a..a90fd91a9c7227e151f7c2ac21bb3c9d1f91ccdb 100644 (file)
@@ -393,7 +393,7 @@ void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code,
        int fault;
 
        /* Protection exception is suppressing, decrement psw address. */
-       regs->psw.addr -= (pgm_int_code >> 16);
+       regs->psw.addr = __rewind_psw(regs->psw, pgm_int_code >> 16);
        /*
         * Check for low-address protection.  This needs to be treated
         * as a special case because the translation exception code