aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2011-10-30 10:16:51 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2011-10-30 10:16:43 -0400
commitd4e81b35b882d96f059afdb0f98e5b6025973b09 (patch)
tree5485be2f8bb0e31d153bf2b7a8bfa3bcabc457ac /arch/s390
parentb50511e41aa51a89b4176784a670582424bc7db6 (diff)
[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>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/ptrace.h2
-rw-r--r--arch/s390/kernel/compat_signal.c12
-rw-r--r--arch/s390/kernel/ptrace.c25
-rw-r--r--arch/s390/kernel/signal.c14
4 files changed, 29 insertions, 24 deletions
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 6fc00d268143..a65846340d51 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -269,7 +269,7 @@ typedef struct
269#define PSW_MASK_EA 0x0000000100000000UL 269#define PSW_MASK_EA 0x0000000100000000UL
270#define PSW_MASK_BA 0x0000000080000000UL 270#define PSW_MASK_BA 0x0000000080000000UL
271 271
272#define PSW_MASK_USER 0x00003F0000000000UL 272#define PSW_MASK_USER 0x00003F0180000000UL
273 273
274#define PSW_ADDR_AMODE 0x0000000000000000UL 274#define PSW_ADDR_AMODE 0x0000000000000000UL
275#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL 275#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index fd83b69207f5..a1dc6457016c 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -302,7 +302,8 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
302 302
303 regs32.psw.mask = psw32_user_bits | 303 regs32.psw.mask = psw32_user_bits |
304 ((__u32)(regs->psw.mask >> 32) & PSW32_MASK_USER); 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 for (i = 0; i < NUM_GPRS; i++) 307 for (i = 0; i < NUM_GPRS; i++)
307 regs32.gprs[i] = (__u32) regs->gprs[i]; 308 regs32.gprs[i] = (__u32) regs->gprs[i];
308 save_access_regs(current->thread.acrs); 309 save_access_regs(current->thread.acrs);
@@ -328,7 +329,8 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
328 if (err) 329 if (err)
329 return err; 330 return err;
330 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 331 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
331 (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32; 332 (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 |
333 (__u64)(regs32.psw.addr & PSW32_ADDR_AMODE);
332 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN); 334 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
333 for (i = 0; i < NUM_GPRS; i++) 335 for (i = 0; i < NUM_GPRS; i++)
334 regs->gprs[i] = (__u64) regs32.gprs[i]; 336 regs->gprs[i] = (__u64) regs32.gprs[i];
@@ -496,9 +498,9 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
496 /* Set up to return from userspace. If provided, use a stub 498 /* Set up to return from userspace. If provided, use a stub
497 already in userspace. */ 499 already in userspace. */
498 if (ka->sa.sa_flags & SA_RESTORER) { 500 if (ka->sa.sa_flags & SA_RESTORER) {
499 regs->gprs[14] = (__u64) ka->sa.sa_restorer; 501 regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
500 } else { 502 } else {
501 regs->gprs[14] = (__u64) frame->retcode; 503 regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
502 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, 504 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
503 (u16 __user *)(frame->retcode))) 505 (u16 __user *)(frame->retcode)))
504 goto give_sigsegv; 506 goto give_sigsegv;
@@ -510,6 +512,7 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
510 512
511 /* Set up registers for signal handler */ 513 /* Set up registers for signal handler */
512 regs->gprs[15] = (__u64) frame; 514 regs->gprs[15] = (__u64) frame;
515 regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */
513 regs->psw.addr = (__u64) ka->sa.sa_handler; 516 regs->psw.addr = (__u64) ka->sa.sa_handler;
514 517
515 regs->gprs[2] = map_signal(sig); 518 regs->gprs[2] = map_signal(sig);
@@ -573,6 +576,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
573 576
574 /* Set up registers for signal handler */ 577 /* Set up registers for signal handler */
575 regs->gprs[15] = (__u64) frame; 578 regs->gprs[15] = (__u64) frame;
579 regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */
576 regs->psw.addr = (__u64) ka->sa.sa_handler; 580 regs->psw.addr = (__u64) ka->sa.sa_handler;
577 581
578 regs->gprs[2] = map_signal(sig); 582 regs->gprs[2] = map_signal(sig);
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 41e20763886e..450931a45b68 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -170,8 +170,7 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr)
170 tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); 170 tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr);
171 if (addr == (addr_t) &dummy->regs.psw.mask) 171 if (addr == (addr_t) &dummy->regs.psw.mask)
172 /* Return a clean psw mask. */ 172 /* Return a clean psw mask. */
173 tmp = psw_user_bits | (tmp & PSW_MASK_USER) | 173 tmp = psw_user_bits | (tmp & PSW_MASK_USER);
174 PSW_MASK_EA | PSW_MASK_BA;
175 174
176 } else if (addr < (addr_t) &dummy->regs.orig_gpr2) { 175 } else if (addr < (addr_t) &dummy->regs.orig_gpr2) {
177 /* 176 /*
@@ -286,26 +285,17 @@ static inline void __poke_user_per(struct task_struct *child,
286static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) 285static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
287{ 286{
288 struct user *dummy = NULL; 287 struct user *dummy = NULL;
289 addr_t offset, tmp; 288 addr_t offset;
290 289
291 if (addr < (addr_t) &dummy->regs.acrs) { 290 if (addr < (addr_t) &dummy->regs.acrs) {
292 /* 291 /*
293 * psw and gprs are stored on the stack 292 * psw and gprs are stored on the stack
294 */ 293 */
295 tmp = (data & ~PSW_MASK_USER) ^ psw_user_bits;
296 if (addr == (addr_t) &dummy->regs.psw.mask && 294 if (addr == (addr_t) &dummy->regs.psw.mask &&
297#ifdef CONFIG_COMPAT 295 ((data & ~PSW_MASK_USER) != psw_user_bits ||
298 tmp != PSW_MASK_BA && 296 ((data & PSW_MASK_EA) && !(data & PSW_MASK_BA))))
299#endif
300 tmp != (PSW_MASK_EA | PSW_MASK_BA))
301 /* Invalid psw mask. */ 297 /* Invalid psw mask. */
302 return -EINVAL; 298 return -EINVAL;
303#ifndef CONFIG_64BIT
304 if (addr == (addr_t) &dummy->regs.psw.addr)
305 /* I'd like to reject addresses without the
306 high order bit but older gdb's rely on it */
307 data |= PSW_ADDR_AMODE;
308#endif
309 if (addr == (addr_t) &dummy->regs.psw.addr) 299 if (addr == (addr_t) &dummy->regs.psw.addr)
310 /* 300 /*
311 * The debugger changed the instruction address, 301 * The debugger changed the instruction address,
@@ -517,7 +507,8 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
517 tmp = psw32_user_bits | (tmp & PSW32_MASK_USER); 507 tmp = psw32_user_bits | (tmp & PSW32_MASK_USER);
518 } else if (addr == (addr_t) &dummy32->regs.psw.addr) { 508 } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
519 /* Fake a 31 bit psw address. */ 509 /* Fake a 31 bit psw address. */
520 tmp = (__u32) regs->psw.addr | PSW32_ADDR_AMODE; 510 tmp = (__u32) regs->psw.addr |
511 (__u32)(regs->psw.mask & PSW_MASK_BA);
521 } else { 512 } else {
522 /* gpr 0-15 */ 513 /* gpr 0-15 */
523 tmp = *(__u32 *)((addr_t) &regs->psw + addr*2 + 4); 514 tmp = *(__u32 *)((addr_t) &regs->psw + addr*2 + 4);
@@ -615,10 +606,14 @@ static int __poke_user_compat(struct task_struct *child,
615 /* Invalid psw mask. */ 606 /* Invalid psw mask. */
616 return -EINVAL; 607 return -EINVAL;
617 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 608 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
609 (regs->psw.mask & PSW_MASK_BA) |
618 (__u64)(tmp & PSW32_MASK_USER) << 32; 610 (__u64)(tmp & PSW32_MASK_USER) << 32;
619 } else if (addr == (addr_t) &dummy32->regs.psw.addr) { 611 } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
620 /* Build a 64 bit psw address from 31 bit address. */ 612 /* Build a 64 bit psw address from 31 bit address. */
621 regs->psw.addr = (__u64) tmp & PSW32_ADDR_INSN; 613 regs->psw.addr = (__u64) tmp & PSW32_ADDR_INSN;
614 /* Transfer 31 bit amode bit to psw mask. */
615 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_BA) |
616 (__u64)(tmp & PSW32_ADDR_AMODE);
622 /* 617 /*
623 * The debugger changed the instruction address, 618 * The debugger changed the instruction address,
624 * reset system call restart, see signal.c:do_signal 619 * reset system call restart, see signal.c:do_signal
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index c19755815e53..05a85bc14c98 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -117,8 +117,8 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
117 117
118 /* Copy a 'clean' PSW mask to the user to avoid leaking 118 /* Copy a 'clean' PSW mask to the user to avoid leaking
119 information about whether PER is currently on. */ 119 information about whether PER is currently on. */
120 user_sregs.regs.psw.mask = psw_user_bits | PSW_MASK_EA | PSW_MASK_BA | 120 user_sregs.regs.psw.mask = psw_user_bits |
121 (regs->psw.mask & PSW_MASK_USER); 121 (regs->psw.mask & PSW_MASK_USER);
122 user_sregs.regs.psw.addr = regs->psw.addr; 122 user_sregs.regs.psw.addr = regs->psw.addr;
123 memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs)); 123 memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
124 memcpy(&user_sregs.regs.acrs, current->thread.acrs, 124 memcpy(&user_sregs.regs.acrs, current->thread.acrs,
@@ -145,9 +145,13 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
145 err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs)); 145 err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs));
146 if (err) 146 if (err)
147 return err; 147 return err;
148 /* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */
148 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | 149 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
149 (user_sregs.regs.psw.mask & PSW_MASK_USER); 150 (user_sregs.regs.psw.mask & PSW_MASK_USER);
150 regs->psw.addr = PSW_ADDR_AMODE | user_sregs.regs.psw.addr; 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 memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); 155 memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
152 memcpy(&current->thread.acrs, &user_sregs.regs.acrs, 156 memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
153 sizeof(sregs->regs.acrs)); 157 sizeof(sregs->regs.acrs));
@@ -290,6 +294,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,
290 294
291 /* Set up registers for signal handler */ 295 /* Set up registers for signal handler */
292 regs->gprs[15] = (unsigned long) frame; 296 regs->gprs[15] = (unsigned long) frame;
297 regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */
293 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; 298 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
294 299
295 regs->gprs[2] = map_signal(sig); 300 regs->gprs[2] = map_signal(sig);
@@ -358,6 +363,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
358 363
359 /* Set up registers for signal handler */ 364 /* Set up registers for signal handler */
360 regs->gprs[15] = (unsigned long) frame; 365 regs->gprs[15] = (unsigned long) frame;
366 regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */
361 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE; 367 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
362 368
363 regs->gprs[2] = map_signal(sig); 369 regs->gprs[2] = map_signal(sig);