aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2011-10-30 10:16:48 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2011-10-30 10:16:43 -0400
commitccf45cafb0805978e6f13a672caca0e536e87cad (patch)
treef4abcadaf691ee952527ad434db3ab91b6e46e7f /arch/s390
parent20b40a794baf3b4b0320c0a77ce944d5d1a01f25 (diff)
[S390] addressing mode limits and psw address wrapping
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>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/processor.h22
-rw-r--r--arch/s390/include/asm/ptrace.h4
-rw-r--r--arch/s390/kernel/signal.c5
-rw-r--r--arch/s390/mm/fault.c2
4 files changed, 29 insertions, 4 deletions
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index a4b6229e5d4b..306c93c1b184 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -187,7 +187,6 @@ static inline void __load_psw(psw_t psw)
187 * Set PSW mask to specified value, while leaving the 187 * Set PSW mask to specified value, while leaving the
188 * PSW addr pointing to the next instruction. 188 * PSW addr pointing to the next instruction.
189 */ 189 */
190
191static inline void __load_psw_mask (unsigned long mask) 190static inline void __load_psw_mask (unsigned long mask)
192{ 191{
193 unsigned long addr; 192 unsigned long addr;
@@ -212,6 +211,27 @@ static inline void __load_psw_mask (unsigned long mask)
212 : "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc"); 211 : "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc");
213#endif /* __s390x__ */ 212#endif /* __s390x__ */
214} 213}
214
215/*
216 * Rewind PSW instruction address by specified number of bytes.
217 */
218static inline unsigned long __rewind_psw(psw_t psw, unsigned long ilc)
219{
220#ifndef __s390x__
221 if (psw.addr & PSW_ADDR_AMODE)
222 /* 31 bit mode */
223 return (psw.addr - ilc) | PSW_ADDR_AMODE;
224 /* 24 bit mode */
225 return (psw.addr - ilc) & ((1UL << 24) - 1);
226#else
227 unsigned long mask;
228
229 mask = (psw.mask & PSW_MASK_EA) ? -1UL :
230 (psw.mask & PSW_MASK_BA) ? (1UL << 31) - 1 :
231 (1UL << 24) - 1;
232 return (psw.addr - ilc) & mask;
233#endif
234}
215 235
216/* 236/*
217 * Function to stop a processor until an interruption occurred 237 * Function to stop a processor until an interruption occurred
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 93c907b4776f..2904cc66967a 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -236,6 +236,8 @@ typedef struct
236#define PSW_MASK_ASC 0x0000C000UL 236#define PSW_MASK_ASC 0x0000C000UL
237#define PSW_MASK_CC 0x00003000UL 237#define PSW_MASK_CC 0x00003000UL
238#define PSW_MASK_PM 0x00000F00UL 238#define PSW_MASK_PM 0x00000F00UL
239#define PSW_MASK_EA 0x00000000UL
240#define PSW_MASK_BA 0x00000000UL
239 241
240#define PSW_ADDR_AMODE 0x80000000UL 242#define PSW_ADDR_AMODE 0x80000000UL
241#define PSW_ADDR_INSN 0x7FFFFFFFUL 243#define PSW_ADDR_INSN 0x7FFFFFFFUL
@@ -261,6 +263,8 @@ typedef struct
261#define PSW_MASK_ASC 0x0000C00000000000UL 263#define PSW_MASK_ASC 0x0000C00000000000UL
262#define PSW_MASK_CC 0x0000300000000000UL 264#define PSW_MASK_CC 0x0000300000000000UL
263#define PSW_MASK_PM 0x00000F0000000000UL 265#define PSW_MASK_PM 0x00000F0000000000UL
266#define PSW_MASK_EA 0x0000000100000000UL
267#define PSW_MASK_BA 0x0000000080000000UL
264 268
265#define PSW_ADDR_AMODE 0x0000000000000000UL 269#define PSW_ADDR_AMODE 0x0000000000000000UL
266#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL 270#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index e751cab80e04..058e372bada1 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -447,8 +447,9 @@ void do_signal(struct pt_regs *regs)
447 /* fallthrough */ 447 /* fallthrough */
448 case -ERESTARTNOINTR: 448 case -ERESTARTNOINTR:
449 regs->gprs[2] = regs->orig_gpr2; 449 regs->gprs[2] = regs->orig_gpr2;
450 regs->psw.addr = regs->psw.addr - 450 regs->psw.addr =
451 (regs->svc_code >> 16); 451 __rewind_psw(regs->psw,
452 regs->svc_code >> 16);
452 break; 453 break;
453 } 454 }
454 /* No longer in a system call */ 455 /* No longer in a system call */
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 9564fc779b27..a90fd91a9c72 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -393,7 +393,7 @@ void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code,
393 int fault; 393 int fault;
394 394
395 /* Protection exception is suppressing, decrement psw address. */ 395 /* Protection exception is suppressing, decrement psw address. */
396 regs->psw.addr -= (pgm_int_code >> 16); 396 regs->psw.addr = __rewind_psw(regs->psw, pgm_int_code >> 16);
397 /* 397 /*
398 * Check for low-address protection. This needs to be treated 398 * Check for low-address protection. This needs to be treated
399 * as a special case because the translation exception code 399 * as a special case because the translation exception code