1 /* MN10300 Misalignment fixup handler
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
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>
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>
30 #include <asm/atomic.h>
32 #include <asm/pgalloc.h>
33 #include <asm/cpu-regs.h>
34 #include <asm/busctl-regs.h>
36 #include <asm/gdb-stub.h>
37 #include <asm/asm-offsets.h>
40 #define kdebug(FMT, ...) printk(KERN_DEBUG "MISALIGN: "FMT"\n", ##__VA_ARGS__)
42 #define kdebug(FMT, ...) do {} while (0)
45 static int misalignment_addr(unsigned long *registers, unsigned params,
46 unsigned opcode, unsigned long disp,
47 void **_address, unsigned long **_postinc);
49 static int misalignment_reg(unsigned long *registers, unsigned params,
50 unsigned opcode, unsigned long disp,
51 unsigned long **_register);
53 static const unsigned Dreg_index[] = {
54 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
57 static const unsigned Areg_index[] = {
58 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2
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
84 u_int8_t opsz, dispsz;
92 [FMT_D2] = { 16, 16 },
93 [FMT_D4] = { 16, 32 },
96 [FMT_D8] = { 24, 24 },
97 [FMT_D9] = { 24, 32 },
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 */
113 RD0, /* reg in displacement in bits 0-3 */
114 RD2, /* reg in displacement in bits 4-7 */
116 SP, /* stack pointer */
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 */
129 IMM32_MEM, /* 32-bit unsigned displacement */
130 IMM32_HIGH8_MEM, /* 32-bit unsigned displacement, LSB in opcode */
148 struct mn10300_opcode {
154 enum format_id format;
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))
166 /* LIBOPCODES EXCERPT
167 Assemble Matsushita MN10300 instructions.
168 Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
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.
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.
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.
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)}},
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}},
300 * fix up misalignment problems where possible
302 asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
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;
310 uint32_t opcode, noc, xo, xm;
313 unsigned tmp, npop, dispsz, loop;
315 kdebug("==>misalignment({pc=%lx})", regs->pc);
318 die("Misalignment trap in interrupt context", regs, code);
320 if (regs->epsw & EPSW_IE)
321 asm volatile("or %0,epsw" : : "i"(EPSW_IE));
326 fixup = search_exception_tables(regs->pc);
328 /* first thing to do is to match the opcode */
329 pc = (u_int8_t *) regs->pc;
331 if (__get_user(byte, pc) != 0)
336 for (pop = mn10300_opcodes; pop->name; pop++) {
337 npop = ilog2(pop->opcode | pop->opmask);
338 if (npop <= 0 || npop > 31)
340 npop = (npop + 8) & ~7;
344 if ((opcode & pop->opmask) == pop->opcode)
346 } else if (npop > noc) {
347 xo = pop->opcode >> (npop - noc);
348 xm = pop->opmask >> (npop - noc);
350 if ((opcode & xm) != xo)
353 /* we've got a partial match (an exact match on the
354 * first N bytes), so we need to get some more data */
356 if (__get_user(byte, pc) != 0)
358 opcode = opcode << 8 | byte;
362 /* there's already been a partial match as long as the
363 * complete match we're now considering, so this one
369 /* didn't manage to find a fixup */
370 if (!user_mode(regs))
371 printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n",
376 if (die_if_no_fixup("misalignment error", regs, code))
379 info.si_signo = SIGBUS;
381 info.si_code = BUS_ADRALN;
382 info.si_addr = (void *) regs->pc;
383 force_sig_info(SIGBUS, &info, current);
386 /* error reading opcodes */
388 if (!user_mode(regs))
390 "MISALIGN: %p: fault whilst reading instruction data\n",
395 if (!user_mode(regs))
397 "MISALIGN: %lx: unsupported addressing mode %x\n",
402 if (!user_mode(regs))
404 "MISALIGN: %lx: unsupported register mode %x\n",
408 unsupported_instruction:
409 if (!user_mode(regs))
411 "MISALIGN: %lx: unsupported instruction %x (%s)\n",
412 regs->pc, opcode, pop->name);
418 regs->pc = fixup->fixup;
421 if (die_if_no_fixup("misalignment fixup", regs, code))
424 info.si_signo = SIGSEGV;
427 info.si_addr = (void *) regs->pc;
428 force_sig_info(SIGSEGV, &info, current);
431 /* we matched the opcode */
433 kdebug("%lx: %x==%x { %x, %x }",
434 regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]);
436 tmp = format_tbl[pop->format].opsz;
438 BUG(); /* match was less complete than it ought to have been */
446 /* grab the extra displacement (note it's LSB first) */
448 dispsz = format_tbl[pop->format].dispsz;
449 for (loop = 0; loop < dispsz; loop += 8) {
451 if (__get_user(byte, pc) != 0)
453 disp |= byte << loop;
454 kdebug("{%p} disp[%02x]=%02x", pc, loop, byte);
457 kdebug("disp=%lx", disp);
460 if (fixup || regs->epsw & EPSW_nSL)
463 tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000;
465 if (!user_mode(regs))
468 " insn not move to/from memory %x\n",
473 if (pop->params[0] & 0x80000000) {
474 /* move memory to register */
475 if (!misalignment_addr(registers, pop->params[0], opcode, disp,
479 if (!misalignment_reg(registers, pop->params[1], opcode, disp,
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)
489 } else if (strcmp(pop->name, "movhu") == 0) {
490 kdebug("movhu (%p),DARn", address);
492 if (copy_from_user(&data, (void *) address, 2) != 0)
493 goto transfer_failed;
494 if (pop->params[0] & 0x1000000)
497 goto unsupported_instruction;
502 /* move register to memory */
503 if (!misalignment_reg(registers, pop->params[0], opcode, disp,
507 if (!misalignment_addr(registers, pop->params[1], opcode, disp,
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)
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)
526 goto unsupported_instruction;
530 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz;
531 regs->pc += tmp >> 3;
538 * determine the address that was being accessed
540 static int misalignment_addr(unsigned long *registers, unsigned params,
541 unsigned opcode, unsigned long disp,
542 void **_address, unsigned long **_postinc)
544 unsigned long *postinc = NULL, address = 0, tmp;
546 params &= 0x7fffffff;
549 switch (params & 0xff) {
551 postinc = ®isters[Dreg_index[opcode & 0x03]];
555 postinc = ®isters[Dreg_index[opcode >> 2 & 0x0c]];
559 postinc = ®isters[Dreg_index[opcode >> 4 & 0x30]];
563 postinc = ®isters[Areg_index[opcode & 0x03]];
567 postinc = ®isters[Areg_index[opcode >> 2 & 0x0c]];
571 postinc = ®isters[Areg_index[opcode >> 4 & 0x30]];
575 postinc = ®isters[Rreg_index[opcode & 0x0f]];
579 postinc = ®isters[Rreg_index[opcode >> 2 & 0x0f]];
583 postinc = ®isters[Rreg_index[opcode >> 4 & 0x0f]];
587 postinc = ®isters[Rreg_index[opcode >> 8 & 0x0f]];
591 postinc = ®isters[Rreg_index[opcode >> 12 & 0x0f]];
595 postinc = ®isters[Rreg_index[disp & 0x0f]];
599 postinc = ®isters[Rreg_index[disp >> 4 & 0x0f]];
603 address += registers[REG_SP >> 2];
608 address += (int32_t) (int8_t) (disp & 0xff);
611 address += (int32_t) (int16_t) (disp & 0xffff);
615 asm("asr 8,%0" : "=r"(tmp) : "0"(tmp));
619 tmp = opcode >> 4 & 0x0f;
621 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
625 address += disp & 0x00ffffff;
630 case IMM32_HIGH8_MEM:
636 } while ((params >>= 8));
638 *_address = (void *) address;
644 * determine the register that is acting as source/dest
646 static int misalignment_reg(unsigned long *registers, unsigned params,
647 unsigned opcode, unsigned long disp,
648 unsigned long **_register)
650 params &= 0x7fffffff;
652 if (params & 0xffffff00)
655 switch (params & 0xff) {
657 *_register = ®isters[Dreg_index[opcode & 0x03]];
660 *_register = ®isters[Dreg_index[opcode >> 2 & 0x03]];
663 *_register = ®isters[Dreg_index[opcode >> 4 & 0x03]];
666 *_register = ®isters[Areg_index[opcode & 0x03]];
669 *_register = ®isters[Areg_index[opcode >> 2 & 0x03]];
672 *_register = ®isters[Areg_index[opcode >> 4 & 0x03]];
675 *_register = ®isters[Rreg_index[opcode & 0x0f]];
678 *_register = ®isters[Rreg_index[opcode >> 2 & 0x0f]];
681 *_register = ®isters[Rreg_index[opcode >> 4 & 0x0f]];
684 *_register = ®isters[Rreg_index[opcode >> 8 & 0x0f]];
687 *_register = ®isters[Rreg_index[opcode >> 12 & 0x0f]];
690 *_register = ®isters[Rreg_index[disp & 0x0f]];
693 *_register = ®isters[Rreg_index[disp >> 4 & 0x0f]];
696 *_register = ®isters[REG_SP >> 2];
707 * misalignment handler tests
709 #ifdef CONFIG_TEST_MISALIGNMENT_HANDLER
710 static u8 __initdata testbuf[512] __attribute__((aligned(16))) = {
717 #define ASSERTCMP(X, OP, Y) \
719 if (unlikely(!((X) OP (Y)))) { \
720 printk(KERN_ERR "\n"); \
721 printk(KERN_ERR "MISALIGN: Assertion failed at line %u\n", \
723 printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n", \
724 (unsigned long)(X), (unsigned long)(Y)); \
729 static int __init test_misalignment(void)
731 register void *r asm("e0");
732 register u32 y asm("e1");
733 void *p = testbuf, *q;
736 printk(KERN_NOTICE "==>test_misalignment() [testbuf=%p]\n", p);
739 printk(KERN_NOTICE "___ MOV (Am),Dn ___\n");
741 asm volatile("mov (%0),%1" : "+a"(q), "=d"(x));
742 ASSERTCMP(q, ==, p + 256);
743 ASSERTCMP(x, ==, 0x44332211);
745 printk(KERN_NOTICE "___ MOV (256,Am),Dn ___\n");
747 asm volatile("mov (256,%0),%1" : "+a"(q), "=d"(x));
749 ASSERTCMP(x, ==, 0x44332211);
751 printk(KERN_NOTICE "___ MOV (Di,Am),Dn ___\n");
754 asm volatile("mov (%2,%0),%1" : "+a"(q), "=d"(x), "+d"(tmp));
756 ASSERTCMP(x, ==, 0x44332211);
757 ASSERTCMP(tmp, ==, 256);
759 printk(KERN_NOTICE "___ MOV (256,Rm),Rn ___\n");
761 asm volatile("mov (256,%0),%1" : "+r"(r), "=r"(y));
763 ASSERTCMP(y, ==, 0x44332211);
765 printk(KERN_NOTICE "___ MOV (Rm+),Rn ___\n");
767 asm volatile("mov (%0+),%1" : "+r"(r), "=r"(y));
768 ASSERTCMP(r, ==, p + 256 + 4);
769 ASSERTCMP(y, ==, 0x44332211);
771 printk(KERN_NOTICE "___ MOV (Rm+,8),Rn ___\n");
773 asm volatile("mov (%0+,8),%1" : "+r"(r), "=r"(y));
774 ASSERTCMP(r, ==, p + 256 + 8);
775 ASSERTCMP(y, ==, 0x44332211);
777 printk(KERN_NOTICE "___ MOV (7,SP),Rn ___\n");
787 "movbu %0,(10,sp) \n"
791 ASSERTCMP(x, ==, 0x44332211);
793 printk(KERN_NOTICE "___ MOV (259,SP),Rn ___\n");
797 "movbu %0,(259,sp) \n"
799 "movbu %0,(260,sp) \n"
801 "movbu %0,(261,sp) \n"
803 "movbu %0,(262,sp) \n"
806 : "+d"(tmp), "=d"(x));
807 ASSERTCMP(x, ==, 0x55332211);
809 printk(KERN_NOTICE "___ MOV (260,SP),Rn ___\n");
813 "movbu %0,(260,sp) \n"
815 "movbu %0,(261,sp) \n"
817 "movbu %0,(262,sp) \n"
819 "movbu %0,(263,sp) \n"
822 : "+d"(tmp), "=d"(x));
823 ASSERTCMP(x, ==, 0x55332211);
826 printk(KERN_NOTICE "___ MOV_LNE ___\n");
836 : "+r"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
839 ASSERTCMP(q, ==, p + 256 + 12);
840 ASSERTCMP(x, ==, 0x44332211);
842 printk(KERN_NOTICE "___ MOV in SETLB ___\n");
852 : "+a"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
856 ASSERTCMP(q, ==, p + 256 + 8);
857 ASSERTCMP(x, ==, 0x44332211);
859 printk(KERN_NOTICE "<==test_misalignment()\n");
863 arch_initcall(test_misalignment);
865 #endif /* CONFIG_TEST_MISALIGNMENT_HANDLER */