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 FMT, ##__VA_ARGS__)
42 #define kdebug(FMT, ...) do {} while (0)
45 static int misalignment_addr(unsigned long *registers, unsigned params,
46 unsigned opcode, unsigned disp,
47 void **_address, unsigned long **_postinc);
49 static int misalignment_reg(unsigned long *registers, unsigned params,
50 unsigned opcode, unsigned disp,
51 unsigned long **_register);
53 static inline unsigned int_log2(unsigned x)
56 asm("bsch %1,%0" : "=r"(y) : "r"(x), "0"(0));
59 #define log2(x) int_log2(x)
61 static const unsigned Dreg_index[] = {
62 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
65 static const unsigned Areg_index[] = {
66 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2
69 static const unsigned Rreg_index[] = {
70 REG_E0 >> 2, REG_E1 >> 2, REG_E2 >> 2, REG_E3 >> 2,
71 REG_E4 >> 2, REG_E5 >> 2, REG_E6 >> 2, REG_E7 >> 2,
72 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2,
73 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
92 u_int8_t opsz, dispsz;
100 [FMT_D2] = { 16, 16 },
101 [FMT_D4] = { 16, 32 },
102 [FMT_D6] = { 24, 0 },
103 [FMT_D7] = { 24, 8 },
104 [FMT_D8] = { 24, 24 },
105 [FMT_D9] = { 24, 32 },
109 DM0, /* data reg in opcode in bits 0-1 */
110 DM1, /* data reg in opcode in bits 2-3 */
111 DM2, /* data reg in opcode in bits 4-5 */
112 AM0, /* addr reg in opcode in bits 0-1 */
113 AM1, /* addr reg in opcode in bits 2-3 */
114 AM2, /* addr reg in opcode in bits 4-5 */
115 RM0, /* reg in opcode in bits 0-3 */
116 RM1, /* reg in opcode in bits 2-5 */
117 RM2, /* reg in opcode in bits 4-7 */
118 RM4, /* reg in opcode in bits 8-11 */
119 RM6, /* reg in opcode in bits 12-15 */
121 RD0, /* reg in displacement in bits 0-3 */
122 RD2, /* reg in displacement in bits 4-7 */
124 SP, /* stack pointer */
126 SD8, /* 8-bit signed displacement */
127 SD16, /* 16-bit signed displacement */
128 SD24, /* 24-bit signed displacement */
129 SIMM4_2, /* 4-bit signed displacement in opcode bits 4-7 */
130 SIMM8, /* 8-bit signed immediate */
131 IMM24, /* 24-bit unsigned immediate */
132 IMM32, /* 32-bit unsigned immediate */
133 IMM32_HIGH8, /* 32-bit unsigned immediate, high 8-bits in opcode */
151 struct mn10300_opcode {
157 enum format_id format;
163 #define MEM(ADDR) (0x80000000 | (ADDR))
164 #define MEM2(ADDR1, ADDR2) (0x80000000 | (ADDR1) << 8 | (ADDR2))
165 #define MEMINC(ADDR) (0x81000000 | (ADDR))
166 #define MEMINC2(ADDR, INC) (0x81000000 | (ADDR) << 8 | (INC))
169 /* LIBOPCODES EXCERPT
170 Assemble Matsushita MN10300 instructions.
171 Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
173 This program is free software; you can redistribute it and/or modify
174 it under the terms of the GNU General Public Licence as published by
175 the Free Software Foundation; either version 2 of the Licence, or
176 (at your option) any later version.
178 This program is distributed in the hope that it will be useful,
179 but WITHOUT ANY WARRANTY; without even the implied warranty of
180 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
181 GNU General Public Licence for more details.
183 You should have received a copy of the GNU General Public Licence
184 along with this program; if not, write to the Free Software
185 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
187 static const struct mn10300_opcode mn10300_opcodes[] = {
188 { "mov", 0x60, 0xf0, 0, FMT_S0, 0, {DM1, MEM(AN0)}},
189 { "mov", 0x70, 0xf0, 0, FMT_S0, 0, {MEM(AM0), DN1}},
190 { "mov", 0xf000, 0xfff0, 0, FMT_D0, 0, {MEM(AM0), AN1}},
191 { "mov", 0xf010, 0xfff0, 0, FMT_D0, 0, {AM1, MEM(AN0)}},
192 { "mov", 0xf300, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), DN2}},
193 { "mov", 0xf340, 0xffc0, 0, FMT_D0, 0, {DM2, MEM2(DI, AN0)}},
194 { "mov", 0xf380, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), AN2}},
195 { "mov", 0xf3c0, 0xffc0, 0, FMT_D0, 0, {AM2, MEM2(DI, AN0)}},
196 { "mov", 0xf80000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8, AM0), DN1}},
197 { "mov", 0xf81000, 0xfff000, 0, FMT_D1, 0, {DM1, MEM2(SD8, AN0)}},
198 { "mov", 0xf82000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8,AM0), AN1}},
199 { "mov", 0xf83000, 0xfff000, 0, FMT_D1, 0, {AM1, MEM2(SD8, AN0)}},
200 { "mov", 0xf8f000, 0xfffc00, 0, FMT_D1, AM33, {MEM2(SD8, AM0), SP}},
201 { "mov", 0xf8f400, 0xfffc00, 0, FMT_D1, AM33, {SP, MEM2(SD8, AN0)}},
202 { "mov", 0xf90a00, 0xffff00, 0, FMT_D6, AM33, {MEM(RM0), RN2}},
203 { "mov", 0xf91a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEM(RN0)}},
204 { "mov", 0xf96a00, 0xffff00, 0x12, FMT_D6, AM33, {MEMINC(RM0), RN2}},
205 { "mov", 0xf97a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEMINC(RN0)}},
206 { "mov", 0xfa000000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), DN1}},
207 { "mov", 0xfa100000, 0xfff00000, 0, FMT_D2, 0, {DM1, MEM2(SD16, AN0)}},
208 { "mov", 0xfa200000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), AN1}},
209 { "mov", 0xfa300000, 0xfff00000, 0, FMT_D2, 0, {AM1, MEM2(SD16, AN0)}},
210 { "mov", 0xfb0a0000, 0xffff0000, 0, FMT_D7, AM33, {MEM2(SD8, RM0), RN2}},
211 { "mov", 0xfb1a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEM2(SD8, RN0)}},
212 { "mov", 0xfb6a0000, 0xffff0000, 0x22, FMT_D7, AM33, {MEMINC2 (RM0, SIMM8), RN2}},
213 { "mov", 0xfb7a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEMINC2 (RN0, SIMM8)}},
214 { "mov", 0xfb8e0000, 0xffff000f, 0, FMT_D7, AM33, {MEM2(RI, RM0), RD2}},
215 { "mov", 0xfb9e0000, 0xffff000f, 0, FMT_D7, AM33, {RD2, MEM2(RI, RN0)}},
216 { "mov", 0xfc000000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), DN1}},
217 { "mov", 0xfc100000, 0xfff00000, 0, FMT_D4, 0, {DM1, MEM2(IMM32,AN0)}},
218 { "mov", 0xfc200000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), AN1}},
219 { "mov", 0xfc300000, 0xfff00000, 0, FMT_D4, 0, {AM1, MEM2(IMM32,AN0)}},
220 { "mov", 0xfd0a0000, 0xffff0000, 0, FMT_D8, AM33, {MEM2(SD24, RM0), RN2}},
221 { "mov", 0xfd1a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEM2(SD24, RN0)}},
222 { "mov", 0xfd6a0000, 0xffff0000, 0x22, FMT_D8, AM33, {MEMINC2 (RM0, IMM24), RN2}},
223 { "mov", 0xfd7a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEMINC2 (RN0, IMM24)}},
224 { "mov", 0xfe0a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}},
225 { "mov", 0xfe1a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}},
226 { "mov", 0xfe6a0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
227 { "mov", 0xfe7a0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
229 { "movhu", 0xf060, 0xfff0, 0, FMT_D0, 0, {MEM(AM0), DN1}},
230 { "movhu", 0xf070, 0xfff0, 0, FMT_D0, 0, {DM1, MEM(AN0)}},
231 { "movhu", 0xf480, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), DN2}},
232 { "movhu", 0xf4c0, 0xffc0, 0, FMT_D0, 0, {DM2, MEM2(DI, AN0)}},
233 { "movhu", 0xf86000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8, AM0), DN1}},
234 { "movhu", 0xf87000, 0xfff000, 0, FMT_D1, 0, {DM1, MEM2(SD8, AN0)}},
235 { "movhu", 0xf94a00, 0xffff00, 0, FMT_D6, AM33, {MEM(RM0), RN2}},
236 { "movhu", 0xf95a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEM(RN0)}},
237 { "movhu", 0xf9ea00, 0xffff00, 0x12, FMT_D6, AM33, {MEMINC(RM0), RN2}},
238 { "movhu", 0xf9fa00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEMINC(RN0)}},
239 { "movhu", 0xfa600000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), DN1}},
240 { "movhu", 0xfa700000, 0xfff00000, 0, FMT_D2, 0, {DM1, MEM2(SD16, AN0)}},
241 { "movhu", 0xfb4a0000, 0xffff0000, 0, FMT_D7, AM33, {MEM2(SD8, RM0), RN2}},
242 { "movhu", 0xfb5a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEM2(SD8, RN0)}},
243 { "movhu", 0xfbce0000, 0xffff000f, 0, FMT_D7, AM33, {MEM2(RI, RM0), RD2}},
244 { "movhu", 0xfbde0000, 0xffff000f, 0, FMT_D7, AM33, {RD2, MEM2(RI, RN0)}},
245 { "movhu", 0xfbea0000, 0xffff0000, 0x22, FMT_D7, AM33, {MEMINC2 (RM0, SIMM8), RN2}},
246 { "movhu", 0xfbfa0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEMINC2 (RN0, SIMM8)}},
247 { "movhu", 0xfc600000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), DN1}},
248 { "movhu", 0xfc700000, 0xfff00000, 0, FMT_D4, 0, {DM1, MEM2(IMM32,AN0)}},
249 { "movhu", 0xfd4a0000, 0xffff0000, 0, FMT_D8, AM33, {MEM2(SD24, RM0), RN2}},
250 { "movhu", 0xfd5a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEM2(SD24, RN0)}},
251 { "movhu", 0xfdea0000, 0xffff0000, 0x22, FMT_D8, AM33, {MEMINC2 (RM0, IMM24), RN2}},
252 { "movhu", 0xfdfa0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEMINC2 (RN0, IMM24)}},
253 { "movhu", 0xfe4a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}},
254 { "movhu", 0xfe5a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}},
255 { "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
256 { "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
257 { 0, 0, 0, 0, 0, 0, {0}},
261 * fix up misalignment problems where possible
263 asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
265 const struct exception_table_entry *fixup;
266 const struct mn10300_opcode *pop;
267 unsigned long *registers = (unsigned long *) regs;
268 unsigned long data, *store, *postinc;
271 uint32_t opcode, disp, noc, xo, xm;
276 kdebug("MISALIGN at %lx\n", regs->pc);
279 die("Misalignment trap in interrupt context", regs, code);
281 if (regs->epsw & EPSW_IE)
282 asm volatile("or %0,epsw" : : "i"(EPSW_IE));
287 fixup = search_exception_tables(regs->pc);
289 /* first thing to do is to match the opcode */
290 pc = (u_int8_t *) regs->pc;
292 if (__get_user(byte, pc) != 0)
297 for (pop = mn10300_opcodes; pop->name; pop++) {
298 npop = log2(pop->opcode | pop->opmask);
299 if (npop <= 0 || npop > 31)
301 npop = (npop + 8) & ~7;
305 if ((opcode & pop->opmask) == pop->opcode)
307 } else if (npop > noc) {
308 xo = pop->opcode >> (npop - noc);
309 xm = pop->opmask >> (npop - noc);
311 if ((opcode & xm) != xo)
314 /* we've got a partial match (an exact match on the
315 * first N bytes), so we need to get some more data */
317 if (__get_user(byte, pc) != 0)
319 opcode = opcode << 8 | byte;
323 /* there's already been a partial match as long as the
324 * complete match we're now considering, so this one
330 /* didn't manage to find a fixup */
331 if (!user_mode(regs))
332 printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n",
337 if (die_if_no_fixup("misalignment error", regs, code))
340 info.si_signo = SIGBUS;
342 info.si_code = BUS_ADRALN;
343 info.si_addr = (void *) regs->pc;
344 force_sig_info(SIGBUS, &info, current);
347 /* error reading opcodes */
349 if (!user_mode(regs))
351 "MISALIGN: %p: fault whilst reading instruction data\n",
356 if (!user_mode(regs))
358 "MISALIGN: %lx: unsupported addressing mode %x\n",
363 if (!user_mode(regs))
365 "MISALIGN: %lx: unsupported register mode %x\n",
369 unsupported_instruction:
370 if (!user_mode(regs))
372 "MISALIGN: %lx: unsupported instruction %x (%s)\n",
373 regs->pc, opcode, pop->name);
379 regs->pc = fixup->fixup;
382 if (die_if_no_fixup("misalignment fixup", regs, code))
385 info.si_signo = SIGSEGV;
388 info.si_addr = (void *) regs->pc;
389 force_sig_info(SIGSEGV, &info, current);
392 /* we matched the opcode */
394 kdebug("MISALIGN: %lx: %x==%x { %x, %x }\n",
395 regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]);
397 tmp = format_tbl[pop->format].opsz;
399 BUG(); /* match was less complete than it ought to have been */
407 /* grab the extra displacement (note it's LSB first) */
409 tmp = format_tbl[pop->format].dispsz >> 3;
415 if (__get_user(byte, pc) != 0)
421 if (fixup || regs->epsw & EPSW_nSL)
424 tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000;
426 if (!user_mode(regs))
429 " insn not move to/from memory %x\n",
434 if (pop->params[0] & 0x80000000) {
435 /* move memory to register */
436 if (!misalignment_addr(registers, pop->params[0], opcode, disp,
440 if (!misalignment_reg(registers, pop->params[1], opcode, disp,
444 if (strcmp(pop->name, "mov") == 0) {
445 kdebug("FIXUP: mov (%p),DARn\n", address);
446 if (copy_from_user(&data, (void *) address, 4) != 0)
447 goto transfer_failed;
448 if (pop->params[0] & 0x1000000)
450 } else if (strcmp(pop->name, "movhu") == 0) {
451 kdebug("FIXUP: movhu (%p),DARn\n", address);
453 if (copy_from_user(&data, (void *) address, 2) != 0)
454 goto transfer_failed;
455 if (pop->params[0] & 0x1000000)
458 goto unsupported_instruction;
463 /* move register to memory */
464 if (!misalignment_reg(registers, pop->params[0], opcode, disp,
468 if (!misalignment_addr(registers, pop->params[1], opcode, disp,
474 if (strcmp(pop->name, "mov") == 0) {
475 kdebug("FIXUP: mov %lx,(%p)\n", data, address);
476 if (copy_to_user((void *) address, &data, 4) != 0)
477 goto transfer_failed;
478 if (pop->params[1] & 0x1000000)
480 } else if (strcmp(pop->name, "movhu") == 0) {
481 kdebug("FIXUP: movhu %hx,(%p)\n",
482 (uint16_t) data, address);
483 if (copy_to_user((void *) address, &data, 2) != 0)
484 goto transfer_failed;
485 if (pop->params[1] & 0x1000000)
488 goto unsupported_instruction;
492 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz;
493 regs->pc += tmp >> 3;
500 * determine the address that was being accessed
502 static int misalignment_addr(unsigned long *registers, unsigned params,
503 unsigned opcode, unsigned disp,
504 void **_address, unsigned long **_postinc)
506 unsigned long *postinc = NULL, address = 0, tmp;
508 params &= 0x7fffffff;
511 switch (params & 0xff) {
513 postinc = ®isters[Dreg_index[opcode & 0x03]];
517 postinc = ®isters[Dreg_index[opcode >> 2 & 0x0c]];
521 postinc = ®isters[Dreg_index[opcode >> 4 & 0x30]];
525 postinc = ®isters[Areg_index[opcode & 0x03]];
529 postinc = ®isters[Areg_index[opcode >> 2 & 0x0c]];
533 postinc = ®isters[Areg_index[opcode >> 4 & 0x30]];
537 postinc = ®isters[Rreg_index[opcode & 0x0f]];
541 postinc = ®isters[Rreg_index[opcode >> 2 & 0x0f]];
545 postinc = ®isters[Rreg_index[opcode >> 4 & 0x0f]];
549 postinc = ®isters[Rreg_index[opcode >> 8 & 0x0f]];
553 postinc = ®isters[Rreg_index[opcode >> 12 & 0x0f]];
557 postinc = ®isters[Rreg_index[disp & 0x0f]];
561 postinc = ®isters[Rreg_index[disp >> 4 & 0x0f]];
567 address += (int32_t) (int8_t) (disp & 0xff);
570 address += (int32_t) (int16_t) (disp & 0xffff);
574 asm("asr 8,%0" : "=r"(tmp) : "0"(tmp));
578 tmp = opcode >> 4 & 0x0f;
580 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
584 address += disp & 0x00ffffff;
593 } while ((params >>= 8));
595 *_address = (void *) address;
601 * determine the register that is acting as source/dest
603 static int misalignment_reg(unsigned long *registers, unsigned params,
604 unsigned opcode, unsigned disp,
605 unsigned long **_register)
607 params &= 0x7fffffff;
609 if (params & 0xffffff00)
612 switch (params & 0xff) {
614 *_register = ®isters[Dreg_index[opcode & 0x03]];
617 *_register = ®isters[Dreg_index[opcode >> 2 & 0x03]];
620 *_register = ®isters[Dreg_index[opcode >> 4 & 0x03]];
623 *_register = ®isters[Areg_index[opcode & 0x03]];
626 *_register = ®isters[Areg_index[opcode >> 2 & 0x03]];
629 *_register = ®isters[Areg_index[opcode >> 4 & 0x03]];
632 *_register = ®isters[Rreg_index[opcode & 0x0f]];
635 *_register = ®isters[Rreg_index[opcode >> 2 & 0x0f]];
638 *_register = ®isters[Rreg_index[opcode >> 4 & 0x0f]];
641 *_register = ®isters[Rreg_index[opcode >> 8 & 0x0f]];
644 *_register = ®isters[Rreg_index[opcode >> 12 & 0x0f]];
647 *_register = ®isters[Rreg_index[disp & 0x0f]];
650 *_register = ®isters[Rreg_index[disp >> 4 & 0x0f]];
653 *_register = ®isters[REG_SP >> 2];