Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

+29 -4
+21 -1
arch/s390/include/asm/processor.h
··· 187 187 * Set PSW mask to specified value, while leaving the 188 188 * PSW addr pointing to the next instruction. 189 189 */ 190 - 191 190 static inline void __load_psw_mask (unsigned long mask) 192 191 { 193 192 unsigned long addr; ··· 210 211 "1:" 211 212 : "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc"); 212 213 #endif /* __s390x__ */ 214 + } 215 + 216 + /* 217 + * Rewind PSW instruction address by specified number of bytes. 218 + */ 219 + static inline unsigned long __rewind_psw(psw_t psw, unsigned long ilc) 220 + { 221 + #ifndef __s390x__ 222 + if (psw.addr & PSW_ADDR_AMODE) 223 + /* 31 bit mode */ 224 + return (psw.addr - ilc) | PSW_ADDR_AMODE; 225 + /* 24 bit mode */ 226 + return (psw.addr - ilc) & ((1UL << 24) - 1); 227 + #else 228 + unsigned long mask; 229 + 230 + mask = (psw.mask & PSW_MASK_EA) ? -1UL : 231 + (psw.mask & PSW_MASK_BA) ? (1UL << 31) - 1 : 232 + (1UL << 24) - 1; 233 + return (psw.addr - ilc) & mask; 234 + #endif 213 235 } 214 236 215 237 /*
+4
arch/s390/include/asm/ptrace.h
··· 236 236 #define PSW_MASK_ASC 0x0000C000UL 237 237 #define PSW_MASK_CC 0x00003000UL 238 238 #define PSW_MASK_PM 0x00000F00UL 239 + #define PSW_MASK_EA 0x00000000UL 240 + #define PSW_MASK_BA 0x00000000UL 239 241 240 242 #define PSW_ADDR_AMODE 0x80000000UL 241 243 #define PSW_ADDR_INSN 0x7FFFFFFFUL ··· 263 261 #define PSW_MASK_ASC 0x0000C00000000000UL 264 262 #define PSW_MASK_CC 0x0000300000000000UL 265 263 #define PSW_MASK_PM 0x00000F0000000000UL 264 + #define PSW_MASK_EA 0x0000000100000000UL 265 + #define PSW_MASK_BA 0x0000000080000000UL 266 266 267 267 #define PSW_ADDR_AMODE 0x0000000000000000UL 268 268 #define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
+3 -2
arch/s390/kernel/signal.c
··· 447 447 /* fallthrough */ 448 448 case -ERESTARTNOINTR: 449 449 regs->gprs[2] = regs->orig_gpr2; 450 - regs->psw.addr = regs->psw.addr - 451 - (regs->svc_code >> 16); 450 + regs->psw.addr = 451 + __rewind_psw(regs->psw, 452 + regs->svc_code >> 16); 452 453 break; 453 454 } 454 455 /* No longer in a system call */
+1 -1
arch/s390/mm/fault.c
··· 393 393 int fault; 394 394 395 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 398 * Check for low-address protection. This needs to be treated 399 399 * as a special case because the translation exception code