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