]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - arch/mn10300/mm/misalignment.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[mv-sheeva.git] / arch / mn10300 / mm / misalignment.c
index 61e65ec47db83ec739c8ec69d2ca9b9b3a6376d9..94c4a43580657a74b594561180759b5d2b43c37c 100644 (file)
@@ -42,8 +42,9 @@
 #define kdebug(FMT, ...) do {} while (0)
 #endif
 
-static int misalignment_addr(unsigned long *registers, unsigned params,
-                            unsigned opcode, unsigned long disp,
+static int misalignment_addr(unsigned long *registers, unsigned long sp,
+                            unsigned params, unsigned opcode,
+                            unsigned long disp,
                             void **_address, unsigned long **_postinc,
                             unsigned long *_inc);
 
@@ -203,8 +204,6 @@ static const struct mn10300_opcode mn10300_opcodes[] = {
 { "mov",       0xf81000,    0xfff000,    0,    FMT_D1, 0,      {DM1, MEM2(SD8, AN0)}},
 { "mov",       0xf82000,    0xfff000,    0,    FMT_D1, 0,      {MEM2(SD8,AM0), AN1}},
 { "mov",       0xf83000,    0xfff000,    0,    FMT_D1, 0,      {AM1, MEM2(SD8, AN0)}},
-{ "mov",       0xf8f000,    0xfffc00,    0,    FMT_D1, AM33,   {MEM2(SD8, AM0), SP}},
-{ "mov",       0xf8f400,    0xfffc00,    0,    FMT_D1, AM33,   {SP, MEM2(SD8, AN0)}},
 { "mov",       0xf90a00,    0xffff00,    0,    FMT_D6, AM33,   {MEM(RM0), RN2}},
 { "mov",       0xf91a00,    0xffff00,    0,    FMT_D6, AM33,   {RM2, MEM(RN0)}},
 { "mov",       0xf96a00,    0xffff00,    0x12, FMT_D6, AM33,   {MEMINC(RM0), RN2}},
@@ -322,7 +321,7 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
        const struct exception_table_entry *fixup;
        const struct mn10300_opcode *pop;
        unsigned long *registers = (unsigned long *) regs;
-       unsigned long data, *store, *postinc, disp, inc;
+       unsigned long data, *store, *postinc, disp, inc, sp;
        mm_segment_t seg;
        siginfo_t info;
        uint32_t opcode, noc, xo, xm;
@@ -330,7 +329,13 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
        void *address;
        unsigned tmp, npop, dispsz, loop;
 
-       kdebug("==>misalignment({pc=%lx})", regs->pc);
+       /* we don't fix up userspace misalignment faults */
+       if (user_mode(regs))
+               goto bus_error;
+
+       sp = (unsigned long) regs + sizeof(*regs);
+
+       kdebug("==>misalignment({pc=%lx,sp=%lx})", regs->pc, sp);
 
        if (regs->epsw & EPSW_IE)
                asm volatile("or %0,epsw" : : "i"(EPSW_IE));
@@ -382,15 +387,15 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
        }
 
        /* didn't manage to find a fixup */
-       if (!user_mode(regs))
-               printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n",
-                      regs->pc, opcode);
+       printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n",
+              regs->pc, opcode);
 
 failed:
        set_fs(seg);
        if (die_if_no_fixup("misalignment error", regs, code))
                return;
 
+bus_error:
        info.si_signo   = SIGBUS;
        info.si_errno   = 0;
        info.si_code    = BUS_ADRALN;
@@ -400,31 +405,27 @@ failed:
 
        /* error reading opcodes */
 fetch_error:
-       if (!user_mode(regs))
-               printk(KERN_CRIT
-                      "MISALIGN: %p: fault whilst reading instruction data\n",
-                      pc);
+       printk(KERN_CRIT
+              "MISALIGN: %p: fault whilst reading instruction data\n",
+              pc);
        goto failed;
 
 bad_addr_mode:
-       if (!user_mode(regs))
-               printk(KERN_CRIT
-                      "MISALIGN: %lx: unsupported addressing mode %x\n",
-                      regs->pc, opcode);
+       printk(KERN_CRIT
+              "MISALIGN: %lx: unsupported addressing mode %x\n",
+              regs->pc, opcode);
        goto failed;
 
 bad_reg_mode:
-       if (!user_mode(regs))
-               printk(KERN_CRIT
-                      "MISALIGN: %lx: unsupported register mode %x\n",
-                      regs->pc, opcode);
+       printk(KERN_CRIT
+              "MISALIGN: %lx: unsupported register mode %x\n",
+              regs->pc, opcode);
        goto failed;
 
 unsupported_instruction:
-       if (!user_mode(regs))
-               printk(KERN_CRIT
-                      "MISALIGN: %lx: unsupported instruction %x (%s)\n",
-                      regs->pc, opcode, pop->name);
+       printk(KERN_CRIT
+              "MISALIGN: %lx: unsupported instruction %x (%s)\n",
+              regs->pc, opcode, pop->name);
        goto failed;
 
 transfer_failed:
@@ -472,16 +473,14 @@ found_opcode:
        kdebug("disp=%lx", disp);
 
        set_fs(KERNEL_XDS);
-       if (fixup || regs->epsw & EPSW_nSL)
+       if (fixup)
                set_fs(seg);
 
        tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000;
        if (!tmp) {
-               if (!user_mode(regs))
-                       printk(KERN_CRIT
-                              "MISALIGN: %lx:"
-                              " insn not move to/from memory %x\n",
-                              regs->pc, opcode);
+               printk(KERN_CRIT
+                      "MISALIGN: %lx: insn not move to/from memory %x\n",
+                      regs->pc, opcode);
                goto failed;
        }
 
@@ -496,7 +495,8 @@ found_opcode:
 
        if (pop->params[0] & 0x80000000) {
                /* move memory to register */
-               if (!misalignment_addr(registers, pop->params[0], opcode, disp,
+               if (!misalignment_addr(registers, sp,
+                                      pop->params[0], opcode, disp,
                                       &address, &postinc, &inc))
                        goto bad_addr_mode;
 
@@ -520,7 +520,8 @@ found_opcode:
                                      &store))
                        goto bad_reg_mode;
 
-               if (!misalignment_addr(registers, pop->params[1], opcode, disp,
+               if (!misalignment_addr(registers, sp,
+                                      pop->params[1], opcode, disp,
                                       &address, &postinc, &inc))
                        goto bad_addr_mode;
 
@@ -542,14 +543,14 @@ found_opcode:
                misalignment_MOV_Lcc(regs, opcode);
 
        set_fs(seg);
-       return;
 }
 
 /*
  * determine the address that was being accessed
  */
-static int misalignment_addr(unsigned long *registers, unsigned params,
-                            unsigned opcode, unsigned long disp,
+static int misalignment_addr(unsigned long *registers, unsigned long sp,
+                            unsigned params, unsigned opcode,
+                            unsigned long disp,
                             void **_address, unsigned long **_postinc,
                             unsigned long *_inc)
 {
@@ -570,11 +571,11 @@ static int misalignment_addr(unsigned long *registers, unsigned params,
                        address += *postinc;
                        break;
                case DM1:
-                       postinc = &registers[Dreg_index[opcode >> 2 & 0x0c]];
+                       postinc = &registers[Dreg_index[opcode >> 2 & 0x03]];
                        address += *postinc;
                        break;
                case DM2:
-                       postinc = &registers[Dreg_index[opcode >> 4 & 0x30]];
+                       postinc = &registers[Dreg_index[opcode >> 4 & 0x03]];
                        address += *postinc;
                        break;
                case AM0:
@@ -582,11 +583,11 @@ static int misalignment_addr(unsigned long *registers, unsigned params,
                        address += *postinc;
                        break;
                case AM1:
-                       postinc = &registers[Areg_index[opcode >> 2 & 0x0c]];
+                       postinc = &registers[Areg_index[opcode >> 2 & 0x03]];
                        address += *postinc;
                        break;
                case AM2:
-                       postinc = &registers[Areg_index[opcode >> 4 & 0x30]];
+                       postinc = &registers[Areg_index[opcode >> 4 & 0x03]];
                        address += *postinc;
                        break;
                case RM0:
@@ -618,7 +619,7 @@ static int misalignment_addr(unsigned long *registers, unsigned params,
                        address += *postinc;
                        break;
                case SP:
-                       address += registers[REG_SP >> 2];
+                       address += sp;
                        break;
 
                        /* displacements are either to be added to the address
@@ -642,6 +643,12 @@ static int misalignment_addr(unsigned long *registers, unsigned params,
                        asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
                        disp = (long) tmp;
                        goto displace_or_inc;
+               case IMM8:
+                       disp &= 0x000000ff;
+                       goto displace_or_inc;
+               case IMM16:
+                       disp &= 0x0000ffff;
+                       goto displace_or_inc;
                case IMM24:
                        disp &= 0x00ffffff;
                        goto displace_or_inc;