sh: Populate initial secondary CPU info from boot_cpu_data.
[safe/jmp/linux-2.6] / arch / powerpc / kernel / align.c
index 3671297..a5b632e 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/system.h>
 #include <asm/cache.h>
 #include <asm/cputable.h>
+#include <asm/emulated_ops.h>
 
 struct aligninfo {
        unsigned char len;
@@ -187,7 +188,7 @@ static struct aligninfo aligninfo[128] = {
        { 4, ST+F+S+U },        /* 11 1 1010: stfsux */
        { 8, ST+F+U },          /* 11 1 1011: stfdux */
        INVALID,                /* 11 1 1100 */
-       INVALID,                /* 11 1 1101 */
+       { 4, LD+F },            /* 11 1 1101: lfiwzx */
        INVALID,                /* 11 1 1110 */
        INVALID,                /* 11 1 1111 */
 };
@@ -367,27 +368,24 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
 static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
                           unsigned int flags)
 {
-       char *ptr = (char *) &current->thread.TS_FPR(reg);
-       int i, ret;
+       char *ptr0 = (char *) &current->thread.TS_FPR(reg);
+       char *ptr1 = (char *) &current->thread.TS_FPR(reg+1);
+       int i, ret, sw = 0;
 
        if (!(flags & F))
                return 0;
        if (reg & 1)
                return 0;       /* invalid form: FRS/FRT must be even */
-       if (!(flags & SW)) {
-               /* not byte-swapped - easy */
-               if (!(flags & ST))
-                       ret = __copy_from_user(ptr, addr, 16);
-               else
-                       ret = __copy_to_user(addr, ptr, 16);
-       } else {
-               /* each FPR value is byte-swapped separately */
-               ret = 0;
-               for (i = 0; i < 16; ++i) {
-                       if (!(flags & ST))
-                               ret |= __get_user(ptr[i^7], addr + i);
-                       else
-                               ret |= __put_user(ptr[i^7], addr + i);
+       if (flags & SW)
+               sw = 7;
+       ret = 0;
+       for (i = 0; i < 8; ++i) {
+               if (!(flags & ST)) {
+                       ret |= __get_user(ptr0[i^sw], addr + i);
+                       ret |= __get_user(ptr1[i^sw], addr + i + 8);
+               } else {
+                       ret |= __put_user(ptr0[i^sw], addr + i);
+                       ret |= __put_user(ptr1[i^sw], addr + i + 8);
                }
        }
        if (ret)
@@ -646,11 +644,16 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
                       unsigned int areg, struct pt_regs *regs,
                       unsigned int flags, unsigned int length)
 {
-       char *ptr = (char *) &current->thread.TS_FPR(reg);
-       int ret;
+       char *ptr;
+       int ret = 0;
 
        flush_vsx_to_thread(current);
 
+       if (reg < 32)
+               ptr = (char *) &current->thread.TS_FPR(reg);
+       else
+               ptr = (char *) &current->thread.vr[reg - 32];
+
        if (flags & ST)
                ret = __copy_to_user(addr, ptr, length);
         else {
@@ -728,8 +731,10 @@ int fix_alignment(struct pt_regs *regs)
        areg = dsisr & 0x1f;            /* register to update */
 
 #ifdef CONFIG_SPE
-       if ((instr >> 26) == 0x4)
+       if ((instr >> 26) == 0x4) {
+               PPC_WARN_EMULATED(spe);
                return emulate_spe(regs, reg, instr);
+       }
 #endif
 
        instr = (dsisr >> 10) & 0x7f;
@@ -781,23 +786,28 @@ int fix_alignment(struct pt_regs *regs)
                        flags |= SPLT;
                        nb = 8;
                }
+               PPC_WARN_EMULATED(vsx);
                return emulate_vsx(addr, reg, areg, regs, flags, nb);
        }
 #endif
        /* A size of 0 indicates an instruction we don't support, with
         * the exception of DCBZ which is handled as a special case here
         */
-       if (instr == DCBZ)
+       if (instr == DCBZ) {
+               PPC_WARN_EMULATED(dcbz);
                return emulate_dcbz(regs, addr);
+       }
        if (unlikely(nb == 0))
                return 0;
 
        /* Load/Store Multiple instructions are handled in their own
         * function
         */
-       if (flags & M)
+       if (flags & M) {
+               PPC_WARN_EMULATED(multiple);
                return emulate_multiple(regs, addr, reg, nb,
                                        flags, instr, swiz);
+       }
 
        /* Verify the address of the operand */
        if (unlikely(user_mode(regs) &&
@@ -814,8 +824,12 @@ int fix_alignment(struct pt_regs *regs)
        }
 
        /* Special case for 16-byte FP loads and stores */
-       if (nb == 16)
+       if (nb == 16) {
+               PPC_WARN_EMULATED(fp_pair);
                return emulate_fp_pair(addr, reg, flags);
+       }
+
+       PPC_WARN_EMULATED(unaligned);
 
        /* If we are loading, get the data from user space, else
         * get it from register values