aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_64.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-06-07 02:14:40 -0400
committerPaul Mackerras <paulus@samba.org>2006-06-09 07:24:15 -0400
commitfab5db97e44f76461f76b24adfa8ccb14d4df498 (patch)
tree123026a1a6f1702468220189b7410077479ae8a2 /arch/powerpc/kernel/signal_64.c
parent651d765d0b2c72d33430487c8b6ef64c60cd2134 (diff)
[PATCH] powerpc: Implement support for setting little-endian mode via prctl
This adds the PowerPC part of the code to allow processes to change their endian mode via prctl. This also extends the alignment exception handler to be able to fix up alignment exceptions that occur in little-endian mode, both for "PowerPC" little-endian and true little-endian. We always enter signal handlers in big-endian mode -- the support for little-endian mode does not amount to the creation of a little-endian user/kernel ABI. If the signal handler returns, the endian mode is restored to what it was when the signal was delivered. We have two new kernel CPU feature bits, one for PPC little-endian and one for true little-endian. Most of the classic 32-bit processors support PPC little-endian, and this is reflected in the CPU feature table. There are two corresponding feature bits reported to userland in the AT_HWCAP aux vector entry. This is based on an earlier patch by Anton Blanchard. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/signal_64.c')
-rw-r--r--arch/powerpc/kernel/signal_64.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 23ba69c26913..66a5fbe31989 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -141,9 +141,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
141 unsigned long err = 0; 141 unsigned long err = 0;
142 unsigned long save_r13 = 0; 142 unsigned long save_r13 = 0;
143 elf_greg_t *gregs = (elf_greg_t *)regs; 143 elf_greg_t *gregs = (elf_greg_t *)regs;
144#ifdef CONFIG_ALTIVEC
145 unsigned long msr; 144 unsigned long msr;
146#endif
147 int i; 145 int i;
148 146
149 /* If this is not a signal return, we preserve the TLS in r13 */ 147 /* If this is not a signal return, we preserve the TLS in r13 */
@@ -154,7 +152,12 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
154 err |= __copy_from_user(regs, &sc->gp_regs, 152 err |= __copy_from_user(regs, &sc->gp_regs,
155 PT_MSR*sizeof(unsigned long)); 153 PT_MSR*sizeof(unsigned long));
156 154
157 /* skip MSR and SOFTE */ 155 /* get MSR separately, transfer the LE bit if doing signal return */
156 err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
157 if (sig)
158 regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
159
160 /* skip SOFTE */
158 for (i = PT_MSR+1; i <= PT_RESULT; i++) { 161 for (i = PT_MSR+1; i <= PT_RESULT; i++) {
159 if (i == PT_SOFTE) 162 if (i == PT_SOFTE)
160 continue; 163 continue;
@@ -179,7 +182,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
179 182
180#ifdef CONFIG_ALTIVEC 183#ifdef CONFIG_ALTIVEC
181 err |= __get_user(v_regs, &sc->v_regs); 184 err |= __get_user(v_regs, &sc->v_regs);
182 err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
183 if (err) 185 if (err)
184 return err; 186 return err;
185 /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ 187 /* Copy 33 vec registers (vr0..31 and vscr) from the stack */
@@ -410,6 +412,8 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
410 412
411 /* Set up "regs" so we "return" to the signal handler. */ 413 /* Set up "regs" so we "return" to the signal handler. */
412 err |= get_user(regs->nip, &funct_desc_ptr->entry); 414 err |= get_user(regs->nip, &funct_desc_ptr->entry);
415 /* enter the signal handler in big-endian mode */
416 regs->msr &= ~MSR_LE;
413 regs->gpr[1] = newsp; 417 regs->gpr[1] = newsp;
414 err |= get_user(regs->gpr[2], &funct_desc_ptr->toc); 418 err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
415 regs->gpr[3] = signr; 419 regs->gpr[3] = signr;