aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_32.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_32.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_32.c')
-rw-r--r--arch/powerpc/kernel/signal_32.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 22f078984845..237faeec2ec2 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -419,9 +419,7 @@ static long restore_user_regs(struct pt_regs *regs,
419{ 419{
420 long err; 420 long err;
421 unsigned int save_r2 = 0; 421 unsigned int save_r2 = 0;
422#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE)
423 unsigned long msr; 422 unsigned long msr;
424#endif
425 423
426 /* 424 /*
427 * restore general registers but not including MSR or SOFTE. Also 425 * restore general registers but not including MSR or SOFTE. Also
@@ -430,11 +428,16 @@ static long restore_user_regs(struct pt_regs *regs,
430 if (!sig) 428 if (!sig)
431 save_r2 = (unsigned int)regs->gpr[2]; 429 save_r2 = (unsigned int)regs->gpr[2];
432 err = restore_general_regs(regs, sr); 430 err = restore_general_regs(regs, sr);
431 err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
433 if (!sig) 432 if (!sig)
434 regs->gpr[2] = (unsigned long) save_r2; 433 regs->gpr[2] = (unsigned long) save_r2;
435 if (err) 434 if (err)
436 return 1; 435 return 1;
437 436
437 /* if doing signal return, restore the previous little-endian mode */
438 if (sig)
439 regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
440
438 /* 441 /*
439 * Do this before updating the thread state in 442 * Do this before updating the thread state in
440 * current->thread.fpr/vr/evr. That way, if we get preempted 443 * current->thread.fpr/vr/evr. That way, if we get preempted
@@ -455,7 +458,7 @@ static long restore_user_regs(struct pt_regs *regs,
455 /* force the process to reload the altivec registers from 458 /* force the process to reload the altivec registers from
456 current->thread when it next does altivec instructions */ 459 current->thread when it next does altivec instructions */
457 regs->msr &= ~MSR_VEC; 460 regs->msr &= ~MSR_VEC;
458 if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_VEC) != 0) { 461 if (msr & MSR_VEC) {
459 /* restore altivec registers from the stack */ 462 /* restore altivec registers from the stack */
460 if (__copy_from_user(current->thread.vr, &sr->mc_vregs, 463 if (__copy_from_user(current->thread.vr, &sr->mc_vregs,
461 sizeof(sr->mc_vregs))) 464 sizeof(sr->mc_vregs)))
@@ -472,7 +475,7 @@ static long restore_user_regs(struct pt_regs *regs,
472 /* force the process to reload the spe registers from 475 /* force the process to reload the spe registers from
473 current->thread when it next does spe instructions */ 476 current->thread when it next does spe instructions */
474 regs->msr &= ~MSR_SPE; 477 regs->msr &= ~MSR_SPE;
475 if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_SPE) != 0) { 478 if (msr & MSR_SPE) {
476 /* restore spe registers from the stack */ 479 /* restore spe registers from the stack */
477 if (__copy_from_user(current->thread.evr, &sr->mc_vregs, 480 if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
478 ELF_NEVRREG * sizeof(u32))) 481 ELF_NEVRREG * sizeof(u32)))
@@ -777,6 +780,8 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
777 regs->gpr[5] = (unsigned long) &rt_sf->uc; 780 regs->gpr[5] = (unsigned long) &rt_sf->uc;
778 regs->gpr[6] = (unsigned long) rt_sf; 781 regs->gpr[6] = (unsigned long) rt_sf;
779 regs->nip = (unsigned long) ka->sa.sa_handler; 782 regs->nip = (unsigned long) ka->sa.sa_handler;
783 /* enter the signal handler in big-endian mode */
784 regs->msr &= ~MSR_LE;
780 regs->trap = 0; 785 regs->trap = 0;
781 return 1; 786 return 1;
782 787
@@ -1047,6 +1052,8 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
1047 regs->gpr[3] = sig; 1052 regs->gpr[3] = sig;
1048 regs->gpr[4] = (unsigned long) sc; 1053 regs->gpr[4] = (unsigned long) sc;
1049 regs->nip = (unsigned long) ka->sa.sa_handler; 1054 regs->nip = (unsigned long) ka->sa.sa_handler;
1055 /* enter the signal handler in big-endian mode */
1056 regs->msr &= ~MSR_LE;
1050 regs->trap = 0; 1057 regs->trap = 0;
1051 1058
1052 return 1; 1059 return 1;