aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/signal.c
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/kernel/signal.c
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/kernel/signal.c')
-rw-r--r--arch/s390/kernel/signal.c14
1 files changed, 10 insertions, 4 deletions
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);