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

[S390] allow all addressing modes

The user space program can change its addressing mode between the
24-bit, 31-bit and the 64-bit mode if the kernel is 64 bit. Currently
the kernel always forces the standard amode on signal delivery and
signal return and on ptrace: 64-bit for a 64-bit process, 31-bit for
a compat process and 31-bit kernels. Change the signal and ptrace code
to allow the full range of addressing modes. Signal handlers are
run in the standard addressing mode for the process.

One caveat is that even an 31-bit compat process can switch to the
64-bit mode. The next signal will switch back into the 31-bit mode
and there is no room in the 31-bit compat signal frame to store the
information that the program came from the 64-bit mode.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

+29 -24
+1 -1
arch/s390/include/asm/ptrace.h
··· 269 269 #define PSW_MASK_EA 0x0000000100000000UL 270 270 #define PSW_MASK_BA 0x0000000080000000UL 271 271 272 - #define PSW_MASK_USER 0x00003F0000000000UL 272 + #define PSW_MASK_USER 0x00003F0180000000UL 273 273 274 274 #define PSW_ADDR_AMODE 0x0000000000000000UL 275 275 #define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
+8 -4
arch/s390/kernel/compat_signal.c
··· 302 302 303 303 regs32.psw.mask = psw32_user_bits | 304 304 ((__u32)(regs->psw.mask >> 32) & PSW32_MASK_USER); 305 - regs32.psw.addr = PSW32_ADDR_AMODE | (__u32) regs->psw.addr; 305 + regs32.psw.addr = (__u32) regs->psw.addr | 306 + (__u32)(regs->psw.mask & PSW_MASK_BA); 306 307 for (i = 0; i < NUM_GPRS; i++) 307 308 regs32.gprs[i] = (__u32) regs->gprs[i]; 308 309 save_access_regs(current->thread.acrs); ··· 329 328 if (err) 330 329 return err; 331 330 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 332 - (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32; 331 + (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 | 332 + (__u64)(regs32.psw.addr & PSW32_ADDR_AMODE); 333 333 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN); 334 334 for (i = 0; i < NUM_GPRS; i++) 335 335 regs->gprs[i] = (__u64) regs32.gprs[i]; ··· 498 496 /* Set up to return from userspace. If provided, use a stub 499 497 already in userspace. */ 500 498 if (ka->sa.sa_flags & SA_RESTORER) { 501 - regs->gprs[14] = (__u64) ka->sa.sa_restorer; 499 + regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE; 502 500 } else { 503 - regs->gprs[14] = (__u64) frame->retcode; 501 + regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE; 504 502 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, 505 503 (u16 __user *)(frame->retcode))) 506 504 goto give_sigsegv; ··· 512 510 513 511 /* Set up registers for signal handler */ 514 512 regs->gprs[15] = (__u64) frame; 513 + regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */ 515 514 regs->psw.addr = (__u64) ka->sa.sa_handler; 516 515 517 516 regs->gprs[2] = map_signal(sig); ··· 576 573 577 574 /* Set up registers for signal handler */ 578 575 regs->gprs[15] = (__u64) frame; 576 + regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */ 579 577 regs->psw.addr = (__u64) ka->sa.sa_handler; 580 578 581 579 regs->gprs[2] = map_signal(sig);
+10 -15
arch/s390/kernel/ptrace.c
··· 170 170 tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); 171 171 if (addr == (addr_t) &dummy->regs.psw.mask) 172 172 /* Return a clean psw mask. */ 173 - tmp = psw_user_bits | (tmp & PSW_MASK_USER) | 174 - PSW_MASK_EA | PSW_MASK_BA; 173 + tmp = psw_user_bits | (tmp & PSW_MASK_USER); 175 174 176 175 } else if (addr < (addr_t) &dummy->regs.orig_gpr2) { 177 176 /* ··· 285 286 static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) 286 287 { 287 288 struct user *dummy = NULL; 288 - addr_t offset, tmp; 289 + addr_t offset; 289 290 290 291 if (addr < (addr_t) &dummy->regs.acrs) { 291 292 /* 292 293 * psw and gprs are stored on the stack 293 294 */ 294 - tmp = (data & ~PSW_MASK_USER) ^ psw_user_bits; 295 295 if (addr == (addr_t) &dummy->regs.psw.mask && 296 - #ifdef CONFIG_COMPAT 297 - tmp != PSW_MASK_BA && 298 - #endif 299 - tmp != (PSW_MASK_EA | PSW_MASK_BA)) 296 + ((data & ~PSW_MASK_USER) != psw_user_bits || 297 + ((data & PSW_MASK_EA) && !(data & PSW_MASK_BA)))) 300 298 /* Invalid psw mask. */ 301 299 return -EINVAL; 302 - #ifndef CONFIG_64BIT 303 - if (addr == (addr_t) &dummy->regs.psw.addr) 304 - /* I'd like to reject addresses without the 305 - high order bit but older gdb's rely on it */ 306 - data |= PSW_ADDR_AMODE; 307 - #endif 308 300 if (addr == (addr_t) &dummy->regs.psw.addr) 309 301 /* 310 302 * The debugger changed the instruction address, ··· 507 517 tmp = psw32_user_bits | (tmp & PSW32_MASK_USER); 508 518 } else if (addr == (addr_t) &dummy32->regs.psw.addr) { 509 519 /* Fake a 31 bit psw address. */ 510 - tmp = (__u32) regs->psw.addr | PSW32_ADDR_AMODE; 520 + tmp = (__u32) regs->psw.addr | 521 + (__u32)(regs->psw.mask & PSW_MASK_BA); 511 522 } else { 512 523 /* gpr 0-15 */ 513 524 tmp = *(__u32 *)((addr_t) &regs->psw + addr*2 + 4); ··· 606 615 /* Invalid psw mask. */ 607 616 return -EINVAL; 608 617 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 618 + (regs->psw.mask & PSW_MASK_BA) | 609 619 (__u64)(tmp & PSW32_MASK_USER) << 32; 610 620 } else if (addr == (addr_t) &dummy32->regs.psw.addr) { 611 621 /* Build a 64 bit psw address from 31 bit address. */ 612 622 regs->psw.addr = (__u64) tmp & PSW32_ADDR_INSN; 623 + /* Transfer 31 bit amode bit to psw mask. */ 624 + regs->psw.mask = (regs->psw.mask & ~PSW_MASK_BA) | 625 + (__u64)(tmp & PSW32_ADDR_AMODE); 613 626 /* 614 627 * The debugger changed the instruction address, 615 628 * reset system call restart, see signal.c:do_signal
+10 -4
arch/s390/kernel/signal.c
··· 117 117 118 118 /* Copy a 'clean' PSW mask to the user to avoid leaking 119 119 information about whether PER is currently on. */ 120 - user_sregs.regs.psw.mask = psw_user_bits | PSW_MASK_EA | PSW_MASK_BA | 121 - (regs->psw.mask & PSW_MASK_USER); 120 + user_sregs.regs.psw.mask = psw_user_bits | 121 + (regs->psw.mask & PSW_MASK_USER); 122 122 user_sregs.regs.psw.addr = regs->psw.addr; 123 123 memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs)); 124 124 memcpy(&user_sregs.regs.acrs, current->thread.acrs, ··· 145 145 err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs)); 146 146 if (err) 147 147 return err; 148 + /* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */ 148 149 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 149 - (user_sregs.regs.psw.mask & PSW_MASK_USER); 150 - regs->psw.addr = PSW_ADDR_AMODE | user_sregs.regs.psw.addr; 150 + (user_sregs.regs.psw.mask & PSW_MASK_USER); 151 + /* Check for invalid amode */ 152 + if (regs->psw.mask & PSW_MASK_EA) 153 + regs->psw.mask |= PSW_MASK_BA; 154 + regs->psw.addr = user_sregs.regs.psw.addr; 151 155 memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); 152 156 memcpy(&current->thread.acrs, &user_sregs.regs.acrs, 153 157 sizeof(sregs->regs.acrs)); ··· 294 290 295 291 /* Set up registers for signal handler */ 296 292 regs->gprs[15] = (unsigned long) frame; 293 + regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */ 297 294 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; 298 295 299 296 regs->gprs[2] = map_signal(sig); ··· 363 358 364 359 /* Set up registers for signal handler */ 365 360 regs->gprs[15] = (unsigned long) frame; 361 + regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */ 366 362 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; 367 363 368 364 regs->gprs[2] = map_signal(sig);