Merge branch 'for-linus' of git://brick.kernel.dk/data/git/linux-2.6-block
[sfrench/cifs-2.6.git] / arch / powerpc / kernel / signal_32.c
index 8fdeca2d4597c35295271ff9ea844a91ea856a4d..6b405a3f43f943b67c5b3cd2cabaeed43847aa00 100644 (file)
@@ -17,7 +17,6 @@
  *  2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -37,7 +36,7 @@
 #include <linux/stddef.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
-#include <linux/suspend.h>
+#include <linux/freezer.h>
 #endif
 
 #include <asm/uaccess.h>
@@ -419,9 +418,7 @@ static long restore_user_regs(struct pt_regs *regs,
 {
        long err;
        unsigned int save_r2 = 0;
-#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE)
        unsigned long msr;
-#endif
 
        /*
         * restore general registers but not including MSR or SOFTE. Also
@@ -430,11 +427,16 @@ static long restore_user_regs(struct pt_regs *regs,
        if (!sig)
                save_r2 = (unsigned int)regs->gpr[2];
        err = restore_general_regs(regs, sr);
+       err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
        if (!sig)
                regs->gpr[2] = (unsigned long) save_r2;
        if (err)
                return 1;
 
+       /* if doing signal return, restore the previous little-endian mode */
+       if (sig)
+               regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
+
        /*
         * Do this before updating the thread state in
         * current->thread.fpr/vr/evr.  That way, if we get preempted
@@ -455,7 +457,7 @@ static long restore_user_regs(struct pt_regs *regs,
        /* force the process to reload the altivec registers from
           current->thread when it next does altivec instructions */
        regs->msr &= ~MSR_VEC;
-       if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_VEC) != 0) {
+       if (msr & MSR_VEC) {
                /* restore altivec registers from the stack */
                if (__copy_from_user(current->thread.vr, &sr->mc_vregs,
                                     sizeof(sr->mc_vregs)))
@@ -472,7 +474,7 @@ static long restore_user_regs(struct pt_regs *regs,
        /* force the process to reload the spe registers from
           current->thread when it next does spe instructions */
        regs->msr &= ~MSR_SPE;
-       if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_SPE) != 0) {
+       if (msr & MSR_SPE) {
                /* restore spe registers from the stack */
                if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
                                     ELF_NEVRREG * sizeof(u32)))
@@ -757,10 +759,10 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
 
        /* Save user registers on the stack */
        frame = &rt_sf->uc.uc_mcontext;
-       if (vdso32_rt_sigtramp && current->thread.vdso_base) {
+       if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
                if (save_user_regs(regs, frame, 0))
                        goto badframe;
-               regs->link = current->thread.vdso_base + vdso32_rt_sigtramp;
+               regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp;
        } else {
                if (save_user_regs(regs, frame, __NR_rt_sigreturn))
                        goto badframe;
@@ -777,6 +779,8 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
        regs->gpr[5] = (unsigned long) &rt_sf->uc;
        regs->gpr[6] = (unsigned long) rt_sf;
        regs->nip = (unsigned long) ka->sa.sa_handler;
+       /* enter the signal handler in big-endian mode */
+       regs->msr &= ~MSR_LE;
        regs->trap = 0;
        return 1;
 
@@ -831,11 +835,21 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
                return -EINVAL;
 
        if (old_ctx != NULL) {
+               struct mcontext __user *mctx;
+
+               /*
+                * old_ctx might not be 16-byte aligned, in which
+                * case old_ctx->uc_mcontext won't be either.
+                * Because we have the old_ctx->uc_pad2 field
+                * before old_ctx->uc_mcontext, we need to round down
+                * from &old_ctx->uc_mcontext to a 16-byte boundary.
+                */
+               mctx = (struct mcontext __user *)
+                       ((unsigned long) &old_ctx->uc_mcontext & ~0xfUL);
                if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
-                   || save_user_regs(regs, &old_ctx->uc_mcontext, 0)
+                   || save_user_regs(regs, mctx, 0)
                    || put_sigset_t(&old_ctx->uc_sigmask, &current->blocked)
-                   || __put_user(to_user_ptr(&old_ctx->uc_mcontext),
-                           &old_ctx->uc_regs))
+                   || __put_user(to_user_ptr(mctx), &old_ctx->uc_regs))
                        return -EFAULT;
        }
        if (new_ctx == NULL)
@@ -1038,10 +1052,10 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
            || __put_user(sig, &sc->signal))
                goto badframe;
 
-       if (vdso32_sigtramp && current->thread.vdso_base) {
+       if (vdso32_sigtramp && current->mm->context.vdso_base) {
                if (save_user_regs(regs, &frame->mctx, 0))
                        goto badframe;
-               regs->link = current->thread.vdso_base + vdso32_sigtramp;
+               regs->link = current->mm->context.vdso_base + vdso32_sigtramp;
        } else {
                if (save_user_regs(regs, &frame->mctx, __NR_sigreturn))
                        goto badframe;
@@ -1056,6 +1070,8 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
        regs->gpr[3] = sig;
        regs->gpr[4] = (unsigned long) sc;
        regs->nip = (unsigned long) ka->sa.sa_handler;
+       /* enter the signal handler in big-endian mode */
+       regs->msr &= ~MSR_LE;
        regs->trap = 0;
 
        return 1;