Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
[pandora-kernel.git] / arch / powerpc / kernel / signal_32.c
index 22f0789..320353f 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>
@@ -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)))
@@ -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;
 
@@ -803,10 +807,13 @@ static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int
                if (__get_user(cmcp, &ucp->uc_regs))
                        return -EFAULT;
                mcp = (struct mcontext __user *)(u64)cmcp;
+               /* no need to check access_ok(mcp), since mcp < 4GB */
        }
 #else
        if (__get_user(mcp, &ucp->uc_regs))
                return -EFAULT;
+       if (!access_ok(VERIFY_READ, mcp, sizeof(*mcp)))
+               return -EFAULT;
 #endif
        restore_sigmask(&set);
        if (restore_user_regs(regs, mcp, sig))
@@ -908,13 +915,14 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
 {
        struct sig_dbg_op op;
        int i;
+       unsigned char tmp;
        unsigned long new_msr = regs->msr;
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
        unsigned long new_dbcr0 = current->thread.dbcr0;
 #endif
 
        for (i=0; i<ndbg; i++) {
-               if (__copy_from_user(&op, dbg, sizeof(op)))
+               if (copy_from_user(&op, dbg + i, sizeof(op)))
                        return -EFAULT;
                switch (op.dbg_type) {
                case SIG_DBG_SINGLE_STEPPING:
@@ -959,6 +967,11 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
        current->thread.dbcr0 = new_dbcr0;
 #endif
 
+       if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx))
+           || __get_user(tmp, (u8 __user *) ctx)
+           || __get_user(tmp, (u8 __user *) (ctx + 1) - 1))
+               return -EFAULT;
+
        /*
         * If we get a fault copying the context into the kernel's
         * image of the user's registers, we can't just return -EFAULT
@@ -1047,6 +1060,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;