Merge branch 'perfcounters-fixes-for-linus' of git://git.kernel.org/pub/scm/linux...
[linux-2.6] / arch / mn10300 / mm / misalignment.c
1 /* MN10300 Misalignment fixup handler
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 #include <linux/module.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/string.h>
15 #include <linux/errno.h>
16 #include <linux/ptrace.h>
17 #include <linux/timer.h>
18 #include <linux/mm.h>
19 #include <linux/smp.h>
20 #include <linux/smp_lock.h>
21 #include <linux/init.h>
22 #include <linux/delay.h>
23 #include <linux/spinlock.h>
24 #include <linux/interrupt.h>
25 #include <linux/pci.h>
26 #include <asm/processor.h>
27 #include <asm/system.h>
28 #include <asm/uaccess.h>
29 #include <asm/io.h>
30 #include <asm/atomic.h>
31 #include <asm/smp.h>
32 #include <asm/pgalloc.h>
33 #include <asm/cpu-regs.h>
34 #include <asm/busctl-regs.h>
35 #include <asm/fpu.h>
36 #include <asm/gdb-stub.h>
37 #include <asm/asm-offsets.h>
38
39 #if 0
40 #define kdebug(FMT, ...) printk(KERN_DEBUG "MISALIGN: "FMT"\n", ##__VA_ARGS__)
41 #else
42 #define kdebug(FMT, ...) do {} while (0)
43 #endif
44
45 static int misalignment_addr(unsigned long *registers, unsigned long sp,
46                              unsigned params, unsigned opcode,
47                              unsigned long disp,
48                              void **_address, unsigned long **_postinc,
49                              unsigned long *_inc);
50
51 static int misalignment_reg(unsigned long *registers, unsigned params,
52                             unsigned opcode, unsigned long disp,
53                             unsigned long **_register);
54
55 static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode);
56
57 static const unsigned Dreg_index[] = {
58         REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
59 };
60
61 static const unsigned Areg_index[] = {
62         REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2
63 };
64
65 static const unsigned Rreg_index[] = {
66         REG_E0 >> 2, REG_E1 >> 2, REG_E2 >> 2, REG_E3 >> 2,
67         REG_E4 >> 2, REG_E5 >> 2, REG_E6 >> 2, REG_E7 >> 2,
68         REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2,
69         REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
70 };
71
72 enum format_id {
73         FMT_S0,
74         FMT_S1,
75         FMT_S2,
76         FMT_S4,
77         FMT_D0,
78         FMT_D1,
79         FMT_D2,
80         FMT_D4,
81         FMT_D6,
82         FMT_D7,
83         FMT_D8,
84         FMT_D9,
85         FMT_D10,
86 };
87
88 static const struct {
89         u_int8_t opsz, dispsz;
90 } format_tbl[16] = {
91         [FMT_S0]        = { 8,  0       },
92         [FMT_S1]        = { 8,  8       },
93         [FMT_S2]        = { 8,  16      },
94         [FMT_S4]        = { 8,  32      },
95         [FMT_D0]        = { 16, 0       },
96         [FMT_D1]        = { 16, 8       },
97         [FMT_D2]        = { 16, 16      },
98         [FMT_D4]        = { 16, 32      },
99         [FMT_D6]        = { 24, 0       },
100         [FMT_D7]        = { 24, 8       },
101         [FMT_D8]        = { 24, 24      },
102         [FMT_D9]        = { 24, 32      },
103         [FMT_D10]       = { 32, 0       },
104 };
105
106 enum value_id {
107         DM0,            /* data reg in opcode in bits 0-1 */
108         DM1,            /* data reg in opcode in bits 2-3 */
109         DM2,            /* data reg in opcode in bits 4-5 */
110         AM0,            /* addr reg in opcode in bits 0-1 */
111         AM1,            /* addr reg in opcode in bits 2-3 */
112         AM2,            /* addr reg in opcode in bits 4-5 */
113         RM0,            /* reg in opcode in bits 0-3 */
114         RM1,            /* reg in opcode in bits 2-5 */
115         RM2,            /* reg in opcode in bits 4-7 */
116         RM4,            /* reg in opcode in bits 8-11 */
117         RM6,            /* reg in opcode in bits 12-15 */
118
119         RD0,            /* reg in displacement in bits 0-3 */
120         RD2,            /* reg in displacement in bits 4-7 */
121
122         SP,             /* stack pointer */
123
124         SD8,            /* 8-bit signed displacement */
125         SD16,           /* 16-bit signed displacement */
126         SD24,           /* 24-bit signed displacement */
127         SIMM4_2,        /* 4-bit signed displacement in opcode bits 4-7 */
128         SIMM8,          /* 8-bit signed immediate */
129         IMM8,           /* 8-bit unsigned immediate */
130         IMM16,          /* 16-bit unsigned immediate */
131         IMM24,          /* 24-bit unsigned immediate */
132         IMM32,          /* 32-bit unsigned immediate */
133         IMM32_HIGH8,    /* 32-bit unsigned immediate, LSB in opcode */
134
135         IMM32_MEM,      /* 32-bit unsigned displacement */
136         IMM32_HIGH8_MEM, /* 32-bit unsigned displacement, LSB in opcode */
137
138         DN0     = DM0,
139         DN1     = DM1,
140         DN2     = DM2,
141         AN0     = AM0,
142         AN1     = AM1,
143         AN2     = AM2,
144         RN0     = RM0,
145         RN1     = RM1,
146         RN2     = RM2,
147         RN4     = RM4,
148         RN6     = RM6,
149         DI      = DM1,
150         RI      = RM2,
151
152 };
153
154 struct mn10300_opcode {
155         const char      name[8];
156         u_int32_t       opcode;
157         u_int32_t       opmask;
158         unsigned        exclusion;
159
160         enum format_id  format;
161
162         unsigned        cpu_mask;
163 #define AM33    330
164
165         unsigned        params[2];
166 #define MEM(ADDR)               (0x80000000 | (ADDR))
167 #define MEM2(ADDR1, ADDR2)      (0x80000000 | (ADDR1) << 8 | (ADDR2))
168 #define MEMINC(ADDR)            (0x81000000 | (ADDR))
169 #define MEMINC2(ADDR, INC)      (0x81000000 | (ADDR) << 8 | (INC))
170 };
171
172 /* LIBOPCODES EXCERPT
173    Assemble Matsushita MN10300 instructions.
174    Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
175
176    This program is free software; you can redistribute it and/or modify
177    it under the terms of the GNU General Public Licence as published by
178    the Free Software Foundation; either version 2 of the Licence, or
179    (at your option) any later version.
180
181    This program is distributed in the hope that it will be useful,
182    but WITHOUT ANY WARRANTY; without even the implied warranty of
183    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
184    GNU General Public Licence for more details.
185
186    You should have received a copy of the GNU General Public Licence
187    along with this program; if not, write to the Free Software
188    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
189 */
190 static const struct mn10300_opcode mn10300_opcodes[] = {
191 { "mov",        0x4200,      0xf300,      0,    FMT_S1, 0,      {DM1, MEM2(IMM8, SP)}},
192 { "mov",        0x4300,      0xf300,      0,    FMT_S1, 0,      {AM1, MEM2(IMM8, SP)}},
193 { "mov",        0x5800,      0xfc00,      0,    FMT_S1, 0,      {MEM2(IMM8, SP), DN0}},
194 { "mov",        0x5c00,      0xfc00,      0,    FMT_S1, 0,      {MEM2(IMM8, SP), AN0}},
195 { "mov",        0x60,        0xf0,        0,    FMT_S0, 0,      {DM1, MEM(AN0)}},
196 { "mov",        0x70,        0xf0,        0,    FMT_S0, 0,      {MEM(AM0), DN1}},
197 { "mov",        0xf000,      0xfff0,      0,    FMT_D0, 0,      {MEM(AM0), AN1}},
198 { "mov",        0xf010,      0xfff0,      0,    FMT_D0, 0,      {AM1, MEM(AN0)}},
199 { "mov",        0xf300,      0xffc0,      0,    FMT_D0, 0,      {MEM2(DI, AM0), DN2}},
200 { "mov",        0xf340,      0xffc0,      0,    FMT_D0, 0,      {DM2, MEM2(DI, AN0)}},
201 { "mov",        0xf380,      0xffc0,      0,    FMT_D0, 0,      {MEM2(DI, AM0), AN2}},
202 { "mov",        0xf3c0,      0xffc0,      0,    FMT_D0, 0,      {AM2, MEM2(DI, AN0)}},
203 { "mov",        0xf80000,    0xfff000,    0,    FMT_D1, 0,      {MEM2(SD8, AM0), DN1}},
204 { "mov",        0xf81000,    0xfff000,    0,    FMT_D1, 0,      {DM1, MEM2(SD8, AN0)}},
205 { "mov",        0xf82000,    0xfff000,    0,    FMT_D1, 0,      {MEM2(SD8,AM0), AN1}},
206 { "mov",        0xf83000,    0xfff000,    0,    FMT_D1, 0,      {AM1, MEM2(SD8, AN0)}},
207 { "mov",        0xf90a00,    0xffff00,    0,    FMT_D6, AM33,   {MEM(RM0), RN2}},
208 { "mov",        0xf91a00,    0xffff00,    0,    FMT_D6, AM33,   {RM2, MEM(RN0)}},
209 { "mov",        0xf96a00,    0xffff00,    0x12, FMT_D6, AM33,   {MEMINC(RM0), RN2}},
210 { "mov",        0xf97a00,    0xffff00,    0,    FMT_D6, AM33,   {RM2, MEMINC(RN0)}},
211 { "mov",        0xfa000000,  0xfff00000,  0,    FMT_D2, 0,      {MEM2(SD16, AM0), DN1}},
212 { "mov",        0xfa100000,  0xfff00000,  0,    FMT_D2, 0,      {DM1, MEM2(SD16, AN0)}},
213 { "mov",        0xfa200000,  0xfff00000,  0,    FMT_D2, 0,      {MEM2(SD16, AM0), AN1}},
214 { "mov",        0xfa300000,  0xfff00000,  0,    FMT_D2, 0,      {AM1, MEM2(SD16, AN0)}},
215 { "mov",        0xfa900000,  0xfff30000,  0,    FMT_D2, 0,      {AM1, MEM2(IMM16, SP)}},
216 { "mov",        0xfa910000,  0xfff30000,  0,    FMT_D2, 0,      {DM1, MEM2(IMM16, SP)}},
217 { "mov",        0xfab00000,  0xfffc0000,  0,    FMT_D2, 0,      {MEM2(IMM16, SP), AN0}},
218 { "mov",        0xfab40000,  0xfffc0000,  0,    FMT_D2, 0,      {MEM2(IMM16, SP), DN0}},
219 { "mov",        0xfb0a0000,  0xffff0000,  0,    FMT_D7, AM33,   {MEM2(SD8, RM0), RN2}},
220 { "mov",        0xfb1a0000,  0xffff0000,  0,    FMT_D7, AM33,   {RM2, MEM2(SD8, RN0)}},
221 { "mov",        0xfb6a0000,  0xffff0000,  0x22, FMT_D7, AM33,   {MEMINC2 (RM0, SIMM8), RN2}},
222 { "mov",        0xfb7a0000,  0xffff0000,  0,    FMT_D7, AM33,   {RM2, MEMINC2 (RN0, SIMM8)}},
223 { "mov",        0xfb8a0000,  0xffff0f00,  0,    FMT_D7, AM33,   {MEM2(IMM8, SP), RN2}},
224 { "mov",        0xfb8e0000,  0xffff000f,  0,    FMT_D7, AM33,   {MEM2(RI, RM0), RD2}},
225 { "mov",        0xfb9a0000,  0xffff0f00,  0,    FMT_D7, AM33,   {RM2, MEM2(IMM8, SP)}},
226 { "mov",        0xfb9e0000,  0xffff000f,  0,    FMT_D7, AM33,   {RD2, MEM2(RI, RN0)}},
227 { "mov",        0xfc000000,  0xfff00000,  0,    FMT_D4, 0,      {MEM2(IMM32,AM0), DN1}},
228 { "mov",        0xfc100000,  0xfff00000,  0,    FMT_D4, 0,      {DM1, MEM2(IMM32,AN0)}},
229 { "mov",        0xfc200000,  0xfff00000,  0,    FMT_D4, 0,      {MEM2(IMM32,AM0), AN1}},
230 { "mov",        0xfc300000,  0xfff00000,  0,    FMT_D4, 0,      {AM1, MEM2(IMM32,AN0)}},
231 { "mov",        0xfc800000,  0xfff30000,  0,    FMT_D4, 0,      {AM1, MEM(IMM32_MEM)}},
232 { "mov",        0xfc810000,  0xfff30000,  0,    FMT_D4, 0,      {DM1, MEM(IMM32_MEM)}},
233 { "mov",        0xfc900000,  0xfff30000,  0,    FMT_D4, 0,      {AM1, MEM2(IMM32, SP)}},
234 { "mov",        0xfc910000,  0xfff30000,  0,    FMT_D4, 0,      {DM1, MEM2(IMM32, SP)}},
235 { "mov",        0xfca00000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM(IMM32_MEM), AN0}},
236 { "mov",        0xfca40000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM(IMM32_MEM), DN0}},
237 { "mov",        0xfcb00000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM2(IMM32, SP), AN0}},
238 { "mov",        0xfcb40000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM2(IMM32, SP), DN0}},
239 { "mov",        0xfd0a0000,  0xffff0000,  0,    FMT_D8, AM33,   {MEM2(SD24, RM0), RN2}},
240 { "mov",        0xfd1a0000,  0xffff0000,  0,    FMT_D8, AM33,   {RM2, MEM2(SD24, RN0)}},
241 { "mov",        0xfd6a0000,  0xffff0000,  0x22, FMT_D8, AM33,   {MEMINC2 (RM0, IMM24), RN2}},
242 { "mov",        0xfd7a0000,  0xffff0000,  0,    FMT_D8, AM33,   {RM2, MEMINC2 (RN0, IMM24)}},
243 { "mov",        0xfd8a0000,  0xffff0f00,  0,    FMT_D8, AM33,   {MEM2(IMM24, SP), RN2}},
244 { "mov",        0xfd9a0000,  0xffff0f00,  0,    FMT_D8, AM33,   {RM2, MEM2(IMM24, SP)}},
245 { "mov",        0xfe0a0000,  0xffff0000,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8,RM0), RN2}},
246 { "mov",        0xfe0a0000,  0xffff0000,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8,RM0), RN2}},
247 { "mov",        0xfe0e0000,  0xffff0f00,  0,    FMT_D9, AM33,   {MEM(IMM32_HIGH8_MEM), RN2}},
248 { "mov",        0xfe1a0000,  0xffff0000,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, RN0)}},
249 { "mov",        0xfe1a0000,  0xffff0000,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, RN0)}},
250 { "mov",        0xfe1e0000,  0xffff0f00,  0,    FMT_D9, AM33,   {RM2, MEM(IMM32_HIGH8_MEM)}},
251 { "mov",        0xfe6a0000,  0xffff0000,  0x22, FMT_D9, AM33,   {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
252 { "mov",        0xfe7a0000,  0xffff0000,  0,    FMT_D9, AM33,   {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
253 { "mov",        0xfe8a0000,  0xffff0f00,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8, SP), RN2}},
254 { "mov",        0xfe9a0000,  0xffff0f00,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, SP)}},
255
256 { "movhu",      0xf060,      0xfff0,      0,    FMT_D0, 0,      {MEM(AM0), DN1}},
257 { "movhu",      0xf070,      0xfff0,      0,    FMT_D0, 0,      {DM1, MEM(AN0)}},
258 { "movhu",      0xf480,      0xffc0,      0,    FMT_D0, 0,      {MEM2(DI, AM0), DN2}},
259 { "movhu",      0xf4c0,      0xffc0,      0,    FMT_D0, 0,      {DM2, MEM2(DI, AN0)}},
260 { "movhu",      0xf86000,    0xfff000,    0,    FMT_D1, 0,      {MEM2(SD8, AM0), DN1}},
261 { "movhu",      0xf87000,    0xfff000,    0,    FMT_D1, 0,      {DM1, MEM2(SD8, AN0)}},
262 { "movhu",      0xf89300,    0xfff300,    0,    FMT_D1, 0,      {DM1, MEM2(IMM8, SP)}},
263 { "movhu",      0xf8bc00,    0xfffc00,    0,    FMT_D1, 0,      {MEM2(IMM8, SP), DN0}},
264 { "movhu",      0xf94a00,    0xffff00,    0,    FMT_D6, AM33,   {MEM(RM0), RN2}},
265 { "movhu",      0xf95a00,    0xffff00,    0,    FMT_D6, AM33,   {RM2, MEM(RN0)}},
266 { "movhu",      0xf9ea00,    0xffff00,    0x12, FMT_D6, AM33,   {MEMINC(RM0), RN2}},
267 { "movhu",      0xf9fa00,    0xffff00,    0,    FMT_D6, AM33,   {RM2, MEMINC(RN0)}},
268 { "movhu",      0xfa600000,  0xfff00000,  0,    FMT_D2, 0,      {MEM2(SD16, AM0), DN1}},
269 { "movhu",      0xfa700000,  0xfff00000,  0,    FMT_D2, 0,      {DM1, MEM2(SD16, AN0)}},
270 { "movhu",      0xfa930000,  0xfff30000,  0,    FMT_D2, 0,      {DM1, MEM2(IMM16, SP)}},
271 { "movhu",      0xfabc0000,  0xfffc0000,  0,    FMT_D2, 0,      {MEM2(IMM16, SP), DN0}},
272 { "movhu",      0xfb4a0000,  0xffff0000,  0,    FMT_D7, AM33,   {MEM2(SD8, RM0), RN2}},
273 { "movhu",      0xfb5a0000,  0xffff0000,  0,    FMT_D7, AM33,   {RM2, MEM2(SD8, RN0)}},
274 { "movhu",      0xfbca0000,  0xffff0f00,  0,    FMT_D7, AM33,   {MEM2(IMM8, SP), RN2}},
275 { "movhu",      0xfbce0000,  0xffff000f,  0,    FMT_D7, AM33,   {MEM2(RI, RM0), RD2}},
276 { "movhu",      0xfbda0000,  0xffff0f00,  0,    FMT_D7, AM33,   {RM2, MEM2(IMM8, SP)}},
277 { "movhu",      0xfbde0000,  0xffff000f,  0,    FMT_D7, AM33,   {RD2, MEM2(RI, RN0)}},
278 { "movhu",      0xfbea0000,  0xffff0000,  0x22, FMT_D7, AM33,   {MEMINC2 (RM0, SIMM8), RN2}},
279 { "movhu",      0xfbfa0000,  0xffff0000,  0,    FMT_D7, AM33,   {RM2, MEMINC2 (RN0, SIMM8)}},
280 { "movhu",      0xfc600000,  0xfff00000,  0,    FMT_D4, 0,      {MEM2(IMM32,AM0), DN1}},
281 { "movhu",      0xfc700000,  0xfff00000,  0,    FMT_D4, 0,      {DM1, MEM2(IMM32,AN0)}},
282 { "movhu",      0xfc830000,  0xfff30000,  0,    FMT_D4, 0,      {DM1, MEM(IMM32_MEM)}},
283 { "movhu",      0xfc930000,  0xfff30000,  0,    FMT_D4, 0,      {DM1, MEM2(IMM32, SP)}},
284 { "movhu",      0xfcac0000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM(IMM32_MEM), DN0}},
285 { "movhu",      0xfcbc0000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM2(IMM32, SP), DN0}},
286 { "movhu",      0xfd4a0000,  0xffff0000,  0,    FMT_D8, AM33,   {MEM2(SD24, RM0), RN2}},
287 { "movhu",      0xfd5a0000,  0xffff0000,  0,    FMT_D8, AM33,   {RM2, MEM2(SD24, RN0)}},
288 { "movhu",      0xfdca0000,  0xffff0f00,  0,    FMT_D8, AM33,   {MEM2(IMM24, SP), RN2}},
289 { "movhu",      0xfdda0000,  0xffff0f00,  0,    FMT_D8, AM33,   {RM2, MEM2(IMM24, SP)}},
290 { "movhu",      0xfdea0000,  0xffff0000,  0x22, FMT_D8, AM33,   {MEMINC2 (RM0, IMM24), RN2}},
291 { "movhu",      0xfdfa0000,  0xffff0000,  0,    FMT_D8, AM33,   {RM2, MEMINC2 (RN0, IMM24)}},
292 { "movhu",      0xfe4a0000,  0xffff0000,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8,RM0), RN2}},
293 { "movhu",      0xfe4e0000,  0xffff0f00,  0,    FMT_D9, AM33,   {MEM(IMM32_HIGH8_MEM), RN2}},
294 { "movhu",      0xfe5a0000,  0xffff0000,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, RN0)}},
295 { "movhu",      0xfe5e0000,  0xffff0f00,  0,    FMT_D9, AM33,   {RM2, MEM(IMM32_HIGH8_MEM)}},
296 { "movhu",      0xfeca0000,  0xffff0f00,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8, SP), RN2}},
297 { "movhu",      0xfeda0000,  0xffff0f00,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, SP)}},
298 { "movhu",      0xfeea0000,  0xffff0000,  0x22, FMT_D9, AM33,   {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
299 { "movhu",      0xfefa0000,  0xffff0000,  0,    FMT_D9, AM33,   {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
300
301 { "mov_llt",    0xf7e00000,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
302 { "mov_lgt",    0xf7e00001,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
303 { "mov_lge",    0xf7e00002,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
304 { "mov_lle",    0xf7e00003,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
305 { "mov_lcs",    0xf7e00004,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
306 { "mov_lhi",    0xf7e00005,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
307 { "mov_lcc",    0xf7e00006,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
308 { "mov_lls",    0xf7e00007,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
309 { "mov_leq",    0xf7e00008,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
310 { "mov_lne",    0xf7e00009,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
311 { "mov_lra",    0xf7e0000a,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
312
313 { "", 0, 0, 0, 0, 0, {0}},
314 };
315
316 /*
317  * fix up misalignment problems where possible
318  */
319 asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
320 {
321         const struct exception_table_entry *fixup;
322         const struct mn10300_opcode *pop;
323         unsigned long *registers = (unsigned long *) regs;
324         unsigned long data, *store, *postinc, disp, inc, sp;
325         mm_segment_t seg;
326         siginfo_t info;
327         uint32_t opcode, noc, xo, xm;
328         uint8_t *pc, byte, datasz;
329         void *address;
330         unsigned tmp, npop, dispsz, loop;
331
332         /* we don't fix up userspace misalignment faults */
333         if (user_mode(regs))
334                 goto bus_error;
335
336         sp = (unsigned long) regs + sizeof(*regs);
337
338         kdebug("==>misalignment({pc=%lx,sp=%lx})", regs->pc, sp);
339
340         if (regs->epsw & EPSW_IE)
341                 asm volatile("or %0,epsw" : : "i"(EPSW_IE));
342
343         seg = get_fs();
344         set_fs(KERNEL_DS);
345
346         fixup = search_exception_tables(regs->pc);
347
348         /* first thing to do is to match the opcode */
349         pc = (u_int8_t *) regs->pc;
350
351         if (__get_user(byte, pc) != 0)
352                 goto fetch_error;
353         opcode = byte;
354         noc = 8;
355
356         for (pop = mn10300_opcodes; pop->name[0]; pop++) {
357                 npop = ilog2(pop->opcode | pop->opmask);
358                 if (npop <= 0 || npop > 31)
359                         continue;
360                 npop = (npop + 8) & ~7;
361
362         got_more_bits:
363                 if (npop == noc) {
364                         if ((opcode & pop->opmask) == pop->opcode)
365                                 goto found_opcode;
366                 } else if (npop > noc) {
367                         xo = pop->opcode >> (npop - noc);
368                         xm = pop->opmask >> (npop - noc);
369
370                         if ((opcode & xm) != xo)
371                                 continue;
372
373                         /* we've got a partial match (an exact match on the
374                          * first N bytes), so we need to get some more data */
375                         pc++;
376                         if (__get_user(byte, pc) != 0)
377                                 goto fetch_error;
378                         opcode = opcode << 8 | byte;
379                         noc += 8;
380                         goto got_more_bits;
381                 } else {
382                         /* there's already been a partial match as long as the
383                          * complete match we're now considering, so this one
384                          * should't match */
385                         continue;
386                 }
387         }
388
389         /* didn't manage to find a fixup */
390         printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n",
391                regs->pc, opcode);
392
393 failed:
394         set_fs(seg);
395         if (die_if_no_fixup("misalignment error", regs, code))
396                 return;
397
398 bus_error:
399         info.si_signo   = SIGBUS;
400         info.si_errno   = 0;
401         info.si_code    = BUS_ADRALN;
402         info.si_addr    = (void *) regs->pc;
403         force_sig_info(SIGBUS, &info, current);
404         return;
405
406         /* error reading opcodes */
407 fetch_error:
408         printk(KERN_CRIT
409                "MISALIGN: %p: fault whilst reading instruction data\n",
410                pc);
411         goto failed;
412
413 bad_addr_mode:
414         printk(KERN_CRIT
415                "MISALIGN: %lx: unsupported addressing mode %x\n",
416                regs->pc, opcode);
417         goto failed;
418
419 bad_reg_mode:
420         printk(KERN_CRIT
421                "MISALIGN: %lx: unsupported register mode %x\n",
422                regs->pc, opcode);
423         goto failed;
424
425 unsupported_instruction:
426         printk(KERN_CRIT
427                "MISALIGN: %lx: unsupported instruction %x (%s)\n",
428                regs->pc, opcode, pop->name);
429         goto failed;
430
431 transfer_failed:
432         set_fs(seg);
433         if (fixup) {
434                 regs->pc = fixup->fixup;
435                 return;
436         }
437         if (die_if_no_fixup("misalignment fixup", regs, code))
438                 return;
439
440         info.si_signo   = SIGSEGV;
441         info.si_errno   = 0;
442         info.si_code    = 0;
443         info.si_addr    = (void *) regs->pc;
444         force_sig_info(SIGSEGV, &info, current);
445         return;
446
447         /* we matched the opcode */
448 found_opcode:
449         kdebug("%lx: %x==%x { %x, %x }",
450                regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]);
451
452         tmp = format_tbl[pop->format].opsz;
453         if (tmp > noc)
454                 BUG(); /* match was less complete than it ought to have been */
455
456         if (tmp < noc) {
457                 tmp = noc - tmp;
458                 opcode >>= tmp;
459                 pc -= tmp >> 3;
460         }
461
462         /* grab the extra displacement (note it's LSB first) */
463         disp = 0;
464         dispsz = format_tbl[pop->format].dispsz;
465         for (loop = 0; loop < dispsz; loop += 8) {
466                 pc++;
467                 if (__get_user(byte, pc) != 0)
468                         goto fetch_error;
469                 disp |= byte << loop;
470                 kdebug("{%p} disp[%02x]=%02x", pc, loop, byte);
471         }
472
473         kdebug("disp=%lx", disp);
474
475         set_fs(KERNEL_XDS);
476         if (fixup)
477                 set_fs(seg);
478
479         tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000;
480         if (!tmp) {
481                 printk(KERN_CRIT
482                        "MISALIGN: %lx: insn not move to/from memory %x\n",
483                        regs->pc, opcode);
484                 goto failed;
485         }
486
487         /* determine the data transfer size of the move */
488         if (pop->name[3] == 0 || /* "mov" */
489             pop->name[4] == 'l') /* mov_lcc */
490                 inc = datasz = 4;
491         else if (pop->name[3] == 'h') /* movhu */
492                 inc = datasz = 2;
493         else
494                 goto unsupported_instruction;
495
496         if (pop->params[0] & 0x80000000) {
497                 /* move memory to register */
498                 if (!misalignment_addr(registers, sp,
499                                        pop->params[0], opcode, disp,
500                                        &address, &postinc, &inc))
501                         goto bad_addr_mode;
502
503                 if (!misalignment_reg(registers, pop->params[1], opcode, disp,
504                                       &store))
505                         goto bad_reg_mode;
506
507                 kdebug("mov%u (%p),DARn", datasz, address);
508                 if (copy_from_user(&data, (void *) address, datasz) != 0)
509                         goto transfer_failed;
510                 if (pop->params[0] & 0x1000000) {
511                         kdebug("inc=%lx", inc);
512                         *postinc += inc;
513                 }
514
515                 *store = data;
516                 kdebug("loaded %lx", data);
517         } else {
518                 /* move register to memory */
519                 if (!misalignment_reg(registers, pop->params[0], opcode, disp,
520                                       &store))
521                         goto bad_reg_mode;
522
523                 if (!misalignment_addr(registers, sp,
524                                        pop->params[1], opcode, disp,
525                                        &address, &postinc, &inc))
526                         goto bad_addr_mode;
527
528                 data = *store;
529
530                 kdebug("mov%u %lx,(%p)", datasz, data, address);
531                 if (copy_to_user((void *) address, &data, datasz) != 0)
532                         goto transfer_failed;
533                 if (pop->params[1] & 0x1000000)
534                         *postinc += inc;
535         }
536
537         tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz;
538         regs->pc += tmp >> 3;
539
540         /* handle MOV_Lcc, which are currently the only FMT_D10 insns that
541          * access memory */
542         if (pop->format == FMT_D10)
543                 misalignment_MOV_Lcc(regs, opcode);
544
545         set_fs(seg);
546 }
547
548 /*
549  * determine the address that was being accessed
550  */
551 static int misalignment_addr(unsigned long *registers, unsigned long sp,
552                              unsigned params, unsigned opcode,
553                              unsigned long disp,
554                              void **_address, unsigned long **_postinc,
555                              unsigned long *_inc)
556 {
557         unsigned long *postinc = NULL, address = 0, tmp;
558
559         if (!(params & 0x1000000)) {
560                 kdebug("noinc");
561                 *_inc = 0;
562                 _inc = NULL;
563         }
564
565         params &= 0x00ffffff;
566
567         do {
568                 switch (params & 0xff) {
569                 case DM0:
570                         postinc = &registers[Dreg_index[opcode & 0x03]];
571                         address += *postinc;
572                         break;
573                 case DM1:
574                         postinc = &registers[Dreg_index[opcode >> 2 & 0x03]];
575                         address += *postinc;
576                         break;
577                 case DM2:
578                         postinc = &registers[Dreg_index[opcode >> 4 & 0x03]];
579                         address += *postinc;
580                         break;
581                 case AM0:
582                         postinc = &registers[Areg_index[opcode & 0x03]];
583                         address += *postinc;
584                         break;
585                 case AM1:
586                         postinc = &registers[Areg_index[opcode >> 2 & 0x03]];
587                         address += *postinc;
588                         break;
589                 case AM2:
590                         postinc = &registers[Areg_index[opcode >> 4 & 0x03]];
591                         address += *postinc;
592                         break;
593                 case RM0:
594                         postinc = &registers[Rreg_index[opcode & 0x0f]];
595                         address += *postinc;
596                         break;
597                 case RM1:
598                         postinc = &registers[Rreg_index[opcode >> 2 & 0x0f]];
599                         address += *postinc;
600                         break;
601                 case RM2:
602                         postinc = &registers[Rreg_index[opcode >> 4 & 0x0f]];
603                         address += *postinc;
604                         break;
605                 case RM4:
606                         postinc = &registers[Rreg_index[opcode >> 8 & 0x0f]];
607                         address += *postinc;
608                         break;
609                 case RM6:
610                         postinc = &registers[Rreg_index[opcode >> 12 & 0x0f]];
611                         address += *postinc;
612                         break;
613                 case RD0:
614                         postinc = &registers[Rreg_index[disp & 0x0f]];
615                         address += *postinc;
616                         break;
617                 case RD2:
618                         postinc = &registers[Rreg_index[disp >> 4 & 0x0f]];
619                         address += *postinc;
620                         break;
621                 case SP:
622                         address += sp;
623                         break;
624
625                         /* displacements are either to be added to the address
626                          * before use, or, in the case of post-inc addressing,
627                          * to be added into the base register after use */
628                 case SD8:
629                 case SIMM8:
630                         disp = (long) (int8_t) (disp & 0xff);
631                         goto displace_or_inc;
632                 case SD16:
633                         disp = (long) (int16_t) (disp & 0xffff);
634                         goto displace_or_inc;
635                 case SD24:
636                         tmp = disp << 8;
637                         asm("asr 8,%0" : "=r"(tmp) : "0"(tmp));
638                         disp = (long) tmp;
639                         goto displace_or_inc;
640                 case SIMM4_2:
641                         tmp = opcode >> 4 & 0x0f;
642                         tmp <<= 28;
643                         asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
644                         disp = (long) tmp;
645                         goto displace_or_inc;
646                 case IMM8:
647                         disp &= 0x000000ff;
648                         goto displace_or_inc;
649                 case IMM16:
650                         disp &= 0x0000ffff;
651                         goto displace_or_inc;
652                 case IMM24:
653                         disp &= 0x00ffffff;
654                         goto displace_or_inc;
655                 case IMM32:
656                 case IMM32_MEM:
657                 case IMM32_HIGH8:
658                 case IMM32_HIGH8_MEM:
659                 displace_or_inc:
660                         kdebug("%s %lx", _inc ? "incr" : "disp", disp);
661                         if (!_inc)
662                                 address += disp;
663                         else
664                                 *_inc = disp;
665                         break;
666                 default:
667                         BUG();
668                         return 0;
669                 }
670         } while ((params >>= 8));
671
672         *_address = (void *) address;
673         *_postinc = postinc;
674         return 1;
675 }
676
677 /*
678  * determine the register that is acting as source/dest
679  */
680 static int misalignment_reg(unsigned long *registers, unsigned params,
681                             unsigned opcode, unsigned long disp,
682                             unsigned long **_register)
683 {
684         params &= 0x7fffffff;
685
686         if (params & 0xffffff00)
687                 return 0;
688
689         switch (params & 0xff) {
690         case DM0:
691                 *_register = &registers[Dreg_index[opcode & 0x03]];
692                 break;
693         case DM1:
694                 *_register = &registers[Dreg_index[opcode >> 2 & 0x03]];
695                 break;
696         case DM2:
697                 *_register = &registers[Dreg_index[opcode >> 4 & 0x03]];
698                 break;
699         case AM0:
700                 *_register = &registers[Areg_index[opcode & 0x03]];
701                 break;
702         case AM1:
703                 *_register = &registers[Areg_index[opcode >> 2 & 0x03]];
704                 break;
705         case AM2:
706                 *_register = &registers[Areg_index[opcode >> 4 & 0x03]];
707                 break;
708         case RM0:
709                 *_register = &registers[Rreg_index[opcode & 0x0f]];
710                 break;
711         case RM1:
712                 *_register = &registers[Rreg_index[opcode >> 2 & 0x0f]];
713                 break;
714         case RM2:
715                 *_register = &registers[Rreg_index[opcode >> 4 & 0x0f]];
716                 break;
717         case RM4:
718                 *_register = &registers[Rreg_index[opcode >> 8 & 0x0f]];
719                 break;
720         case RM6:
721                 *_register = &registers[Rreg_index[opcode >> 12 & 0x0f]];
722                 break;
723         case RD0:
724                 *_register = &registers[Rreg_index[disp & 0x0f]];
725                 break;
726         case RD2:
727                 *_register = &registers[Rreg_index[disp >> 4 & 0x0f]];
728                 break;
729         case SP:
730                 *_register = &registers[REG_SP >> 2];
731                 break;
732
733         default:
734                 BUG();
735                 return 0;
736         }
737
738         return 1;
739 }
740
741 /*
742  * handle the conditional loop part of the move-and-loop instructions
743  */
744 static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode)
745 {
746         unsigned long epsw = regs->epsw;
747         unsigned long NxorV;
748
749         kdebug("MOV_Lcc %x [flags=%lx]", opcode, epsw & 0xf);
750
751         /* calculate N^V and shift onto the same bit position as Z */
752         NxorV = ((epsw >> 3) ^ epsw >> 1) & 1;
753
754         switch (opcode & 0xf) {
755         case 0x0: /* MOV_LLT: N^V */
756                 if (NxorV)
757                         goto take_the_loop;
758                 return;
759         case 0x1: /* MOV_LGT: ~(Z or (N^V))*/
760                 if (!((epsw & EPSW_FLAG_Z) | NxorV))
761                         goto take_the_loop;
762                 return;
763         case 0x2: /* MOV_LGE: ~(N^V) */
764                 if (!NxorV)
765                         goto take_the_loop;
766                 return;
767         case 0x3: /* MOV_LLE: Z or (N^V) */
768                 if ((epsw & EPSW_FLAG_Z) | NxorV)
769                         goto take_the_loop;
770                 return;
771
772         case 0x4: /* MOV_LCS: C */
773                 if (epsw & EPSW_FLAG_C)
774                         goto take_the_loop;
775                 return;
776         case 0x5: /* MOV_LHI: ~(C or Z) */
777                 if (!(epsw & (EPSW_FLAG_C | EPSW_FLAG_Z)))
778                         goto take_the_loop;
779                 return;
780         case 0x6: /* MOV_LCC: ~C */
781                 if (!(epsw & EPSW_FLAG_C))
782                         goto take_the_loop;
783                 return;
784         case 0x7: /* MOV_LLS: C or Z */
785                 if (epsw & (EPSW_FLAG_C | EPSW_FLAG_Z))
786                         goto take_the_loop;
787                 return;
788
789         case 0x8: /* MOV_LEQ: Z */
790                 if (epsw & EPSW_FLAG_Z)
791                         goto take_the_loop;
792                 return;
793         case 0x9: /* MOV_LNE: ~Z */
794                 if (!(epsw & EPSW_FLAG_Z))
795                         goto take_the_loop;
796                 return;
797         case 0xa: /* MOV_LRA: always */
798                 goto take_the_loop;
799
800         default:
801                 BUG();
802         }
803
804 take_the_loop:
805         /* wind the PC back to just after the SETLB insn */
806         kdebug("loop LAR=%lx", regs->lar);
807         regs->pc = regs->lar - 4;
808 }
809
810 /*
811  * misalignment handler tests
812  */
813 #ifdef CONFIG_TEST_MISALIGNMENT_HANDLER
814 static u8 __initdata testbuf[512] __attribute__((aligned(16))) = {
815         [257] = 0x11,
816         [258] = 0x22,
817         [259] = 0x33,
818         [260] = 0x44,
819 };
820
821 #define ASSERTCMP(X, OP, Y)                                             \
822 do {                                                                    \
823         if (unlikely(!((X) OP (Y)))) {                                  \
824                 printk(KERN_ERR "\n");                                  \
825                 printk(KERN_ERR "MISALIGN: Assertion failed at line %u\n", \
826                        __LINE__);                                       \
827                 printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n",       \
828                        (unsigned long)(X), (unsigned long)(Y));         \
829                 BUG();                                                  \
830         }                                                               \
831 } while(0)
832
833 static int __init test_misalignment(void)
834 {
835         register void *r asm("e0");
836         register u32 y asm("e1");
837         void *p = testbuf, *q;
838         u32 tmp, tmp2, x;
839
840         printk(KERN_NOTICE "==>test_misalignment() [testbuf=%p]\n", p);
841         p++;
842
843         printk(KERN_NOTICE "___ MOV (Am),Dn ___\n");
844         q = p + 256;
845         asm volatile("mov       (%0),%1" : "+a"(q), "=d"(x));
846         ASSERTCMP(q, ==, p + 256);
847         ASSERTCMP(x, ==, 0x44332211);
848
849         printk(KERN_NOTICE "___ MOV (256,Am),Dn ___\n");
850         q = p;
851         asm volatile("mov       (256,%0),%1" : "+a"(q), "=d"(x));
852         ASSERTCMP(q, ==, p);
853         ASSERTCMP(x, ==, 0x44332211);
854
855         printk(KERN_NOTICE "___ MOV (Di,Am),Dn ___\n");
856         tmp = 256;
857         q = p;
858         asm volatile("mov       (%2,%0),%1" : "+a"(q), "=d"(x), "+d"(tmp));
859         ASSERTCMP(q, ==, p);
860         ASSERTCMP(x, ==, 0x44332211);
861         ASSERTCMP(tmp, ==, 256);
862
863         printk(KERN_NOTICE "___ MOV (256,Rm),Rn ___\n");
864         r = p;
865         asm volatile("mov       (256,%0),%1" : "+r"(r), "=r"(y));
866         ASSERTCMP(r, ==, p);
867         ASSERTCMP(y, ==, 0x44332211);
868
869         printk(KERN_NOTICE "___ MOV (Rm+),Rn ___\n");
870         r = p + 256;
871         asm volatile("mov       (%0+),%1" : "+r"(r), "=r"(y));
872         ASSERTCMP(r, ==, p + 256 + 4);
873         ASSERTCMP(y, ==, 0x44332211);
874
875         printk(KERN_NOTICE "___ MOV (Rm+,8),Rn ___\n");
876         r = p + 256;
877         asm volatile("mov       (%0+,8),%1" : "+r"(r), "=r"(y));
878         ASSERTCMP(r, ==, p + 256 + 8);
879         ASSERTCMP(y, ==, 0x44332211);
880
881         printk(KERN_NOTICE "___ MOV (7,SP),Rn ___\n");
882         asm volatile(
883                 "add    -16,sp          \n"
884                 "mov    +0x11,%0        \n"
885                 "movbu  %0,(7,sp)       \n"
886                 "mov    +0x22,%0        \n"
887                 "movbu  %0,(8,sp)       \n"
888                 "mov    +0x33,%0        \n"
889                 "movbu  %0,(9,sp)       \n"
890                 "mov    +0x44,%0        \n"
891                 "movbu  %0,(10,sp)      \n"
892                 "mov    (7,sp),%1       \n"
893                 "add    +16,sp          \n"
894                 : "+a"(q), "=d"(x));
895         ASSERTCMP(x, ==, 0x44332211);
896
897         printk(KERN_NOTICE "___ MOV (259,SP),Rn ___\n");
898         asm volatile(
899                 "add    -264,sp         \n"
900                 "mov    +0x11,%0        \n"
901                 "movbu  %0,(259,sp)     \n"
902                 "mov    +0x22,%0        \n"
903                 "movbu  %0,(260,sp)     \n"
904                 "mov    +0x33,%0        \n"
905                 "movbu  %0,(261,sp)     \n"
906                 "mov    +0x55,%0        \n"
907                 "movbu  %0,(262,sp)     \n"
908                 "mov    (259,sp),%1     \n"
909                 "add    +264,sp         \n"
910                 : "+d"(tmp), "=d"(x));
911         ASSERTCMP(x, ==, 0x55332211);
912
913         printk(KERN_NOTICE "___ MOV (260,SP),Rn ___\n");
914         asm volatile(
915                 "add    -264,sp         \n"
916                 "mov    +0x11,%0        \n"
917                 "movbu  %0,(260,sp)     \n"
918                 "mov    +0x22,%0        \n"
919                 "movbu  %0,(261,sp)     \n"
920                 "mov    +0x33,%0        \n"
921                 "movbu  %0,(262,sp)     \n"
922                 "mov    +0x55,%0        \n"
923                 "movbu  %0,(263,sp)     \n"
924                 "mov    (260,sp),%1     \n"
925                 "add    +264,sp         \n"
926                 : "+d"(tmp), "=d"(x));
927         ASSERTCMP(x, ==, 0x55332211);
928
929
930         printk(KERN_NOTICE "___ MOV_LNE ___\n");
931         tmp = 1;
932         tmp2 = 2;
933         q = p + 256;
934         asm volatile(
935                 "setlb                  \n"
936                 "mov    %2,%3           \n"
937                 "mov    %1,%2           \n"
938                 "cmp    +0,%1           \n"
939                 "mov_lne        (%0+,4),%1"
940                 : "+r"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
941                 :
942                 : "cc");
943         ASSERTCMP(q, ==, p + 256 + 12);
944         ASSERTCMP(x, ==, 0x44332211);
945
946         printk(KERN_NOTICE "___ MOV in SETLB ___\n");
947         tmp = 1;
948         tmp2 = 2;
949         q = p + 256;
950         asm volatile(
951                 "setlb                  \n"
952                 "mov    %1,%3           \n"
953                 "mov    (%0+),%1        \n"
954                 "cmp    +0,%1           \n"
955                 "lne                    "
956                 : "+a"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
957                 :
958                 : "cc");
959
960         ASSERTCMP(q, ==, p + 256 + 8);
961         ASSERTCMP(x, ==, 0x44332211);
962
963         printk(KERN_NOTICE "<==test_misalignment()\n");
964         return 0;
965 }
966
967 arch_initcall(test_misalignment);
968
969 #endif /* CONFIG_TEST_MISALIGNMENT_HANDLER */