aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/mm/misalignment.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-02-08 07:19:31 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:30 -0500
commitb920de1b77b72ca9432ac3f97edb26541e65e5dd (patch)
tree40fa9be1470e929c47927dea7eddf184c0204229 /arch/mn10300/mm/misalignment.c
parentef3d534754f31fed9c3b976fee1ece1b3bc38282 (diff)
mn10300: add the MN10300/AM33 architecture to the kernel
Add architecture support for the MN10300/AM33 CPUs produced by MEI to the kernel. This patch also adds board support for the ASB2303 with the ASB2308 daughter board, and the ASB2305. The only processor supported is the MN103E010, which is an AM33v2 core plus on-chip devices. [akpm@linux-foundation.org: nuke cvs control strings] Signed-off-by: Masakazu Urade <urade.masakazu@jp.panasonic.com> Signed-off-by: Koichi Yasutake <yasutake.koichi@jp.panasonic.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/mn10300/mm/misalignment.c')
-rw-r--r--arch/mn10300/mm/misalignment.c661
1 files changed, 661 insertions, 0 deletions
diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
new file mode 100644
index 000000000000..32aa89dc3848
--- /dev/null
+++ b/arch/mn10300/mm/misalignment.c
@@ -0,0 +1,661 @@
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 FMT, ##__VA_ARGS__)
41#else
42#define kdebug(FMT, ...) do {} while (0)
43#endif
44
45static int misalignment_addr(unsigned long *registers, unsigned params,
46 unsigned opcode, unsigned disp,
47 void **_address, unsigned long **_postinc);
48
49static int misalignment_reg(unsigned long *registers, unsigned params,
50 unsigned opcode, unsigned disp,
51 unsigned long **_register);
52
53static inline unsigned int_log2(unsigned x)
54{
55 unsigned y;
56 asm("bsch %1,%0" : "=r"(y) : "r"(x), "0"(0));
57 return y;
58}
59#define log2(x) int_log2(x)
60
61static const unsigned Dreg_index[] = {
62 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
63};
64
65static const unsigned Areg_index[] = {
66 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2
67};
68
69static 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
74};
75
76enum format_id {
77 FMT_S0,
78 FMT_S1,
79 FMT_S2,
80 FMT_S4,
81 FMT_D0,
82 FMT_D1,
83 FMT_D2,
84 FMT_D4,
85 FMT_D6,
86 FMT_D7,
87 FMT_D8,
88 FMT_D9,
89};
90
91struct {
92 u_int8_t opsz, dispsz;
93} format_tbl[16] = {
94 [FMT_S0] = { 8, 0 },
95 [FMT_S1] = { 8, 8 },
96 [FMT_S2] = { 8, 16 },
97 [FMT_S4] = { 8, 32 },
98 [FMT_D0] = { 16, 0 },
99 [FMT_D1] = { 16, 8 },
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 },
106};
107
108enum value_id {
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 */
120
121 RD0, /* reg in displacement in bits 0-3 */
122 RD2, /* reg in displacement in bits 4-7 */
123
124 SP, /* stack pointer */
125
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 */
134
135 DN0 = DM0,
136 DN1 = DM1,
137 DN2 = DM2,
138 AN0 = AM0,
139 AN1 = AM1,
140 AN2 = AM2,
141 RN0 = RM0,
142 RN1 = RM1,
143 RN2 = RM2,
144 RN4 = RM4,
145 RN6 = RM6,
146 DI = DM1,
147 RI = RM2,
148
149};
150
151struct mn10300_opcode {
152 const char *name;
153 u_int32_t opcode;
154 u_int32_t opmask;
155 unsigned exclusion;
156
157 enum format_id format;
158
159 unsigned cpu_mask;
160#define AM33 330
161
162 unsigned params[2];
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))
167};
168
169/* LIBOPCODES EXCERPT
170 Assemble Matsushita MN10300 instructions.
171 Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
172
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.
177
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.
182
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.
186*/
187static 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)}},
228
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}},
258};
259
260/*
261 * fix up misalignment problems where possible
262 */
263asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
264{
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;
269 mm_segment_t seg;
270 siginfo_t info;
271 uint32_t opcode, disp, noc, xo, xm;
272 uint8_t *pc, byte;
273 void *address;
274 unsigned tmp, npop;
275
276 kdebug("MISALIGN at %lx\n", regs->pc);
277
278 if (in_interrupt())
279 die("Misalignment trap in interrupt context", regs, code);
280
281 if (regs->epsw & EPSW_IE)
282 asm volatile("or %0,epsw" : : "i"(EPSW_IE));
283
284 seg = get_fs();
285 set_fs(KERNEL_DS);
286
287 fixup = search_exception_tables(regs->pc);
288
289 /* first thing to do is to match the opcode */
290 pc = (u_int8_t *) regs->pc;
291
292 if (__get_user(byte, pc) != 0)
293 goto fetch_error;
294 opcode = byte;
295 noc = 8;
296
297 for (pop = mn10300_opcodes; pop->name; pop++) {
298 npop = log2(pop->opcode | pop->opmask);
299 if (npop <= 0 || npop > 31)
300 continue;
301 npop = (npop + 8) & ~7;
302
303 got_more_bits:
304 if (npop == noc) {
305 if ((opcode & pop->opmask) == pop->opcode)
306 goto found_opcode;
307 } else if (npop > noc) {
308 xo = pop->opcode >> (npop - noc);
309 xm = pop->opmask >> (npop - noc);
310
311 if ((opcode & xm) != xo)
312 continue;
313
314 /* we've got a partial match (an exact match on the
315 * first N bytes), so we need to get some more data */
316 pc++;
317 if (__get_user(byte, pc) != 0)
318 goto fetch_error;
319 opcode = opcode << 8 | byte;
320 noc += 8;
321 goto got_more_bits;
322 } else {
323 /* there's already been a partial match as long as the
324 * complete match we're now considering, so this one
325 * should't match */
326 continue;
327 }
328 }
329
330 /* didn't manage to find a fixup */
331 if (!user_mode(regs))
332 printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n",
333 regs->pc, opcode);
334
335failed:
336 set_fs(seg);
337 if (die_if_no_fixup("misalignment error", regs, code))
338 return;
339
340 info.si_signo = SIGBUS;
341 info.si_errno = 0;
342 info.si_code = BUS_ADRALN;
343 info.si_addr = (void *) regs->pc;
344 force_sig_info(SIGBUS, &info, current);
345 return;
346
347 /* error reading opcodes */
348fetch_error:
349 if (!user_mode(regs))
350 printk(KERN_CRIT
351 "MISALIGN: %p: fault whilst reading instruction data\n",
352 pc);
353 goto failed;
354
355bad_addr_mode:
356 if (!user_mode(regs))
357 printk(KERN_CRIT
358 "MISALIGN: %lx: unsupported addressing mode %x\n",
359 regs->pc, opcode);
360 goto failed;
361
362bad_reg_mode:
363 if (!user_mode(regs))
364 printk(KERN_CRIT
365 "MISALIGN: %lx: unsupported register mode %x\n",
366 regs->pc, opcode);
367 goto failed;
368
369unsupported_instruction:
370 if (!user_mode(regs))
371 printk(KERN_CRIT
372 "MISALIGN: %lx: unsupported instruction %x (%s)\n",
373 regs->pc, opcode, pop->name);
374 goto failed;
375
376transfer_failed:
377 set_fs(seg);
378 if (fixup) {
379 regs->pc = fixup->fixup;
380 return;
381 }
382 if (die_if_no_fixup("misalignment fixup", regs, code))
383 return;
384
385 info.si_signo = SIGSEGV;
386 info.si_errno = 0;
387 info.si_code = 0;
388 info.si_addr = (void *) regs->pc;
389 force_sig_info(SIGSEGV, &info, current);
390 return;
391
392 /* we matched the opcode */
393found_opcode:
394 kdebug("MISALIGN: %lx: %x==%x { %x, %x }\n",
395 regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]);
396
397 tmp = format_tbl[pop->format].opsz;
398 if (tmp > noc)
399 BUG(); /* match was less complete than it ought to have been */
400
401 if (tmp < noc) {
402 tmp = noc - tmp;
403 opcode >>= tmp;
404 pc -= tmp >> 3;
405 }
406
407 /* grab the extra displacement (note it's LSB first) */
408 disp = 0;
409 tmp = format_tbl[pop->format].dispsz >> 3;
410 while (tmp > 0) {
411 tmp--;
412 disp <<= 8;
413
414 pc++;
415 if (__get_user(byte, pc) != 0)
416 goto fetch_error;
417 disp |= byte;
418 }
419
420 set_fs(KERNEL_XDS);
421 if (fixup || regs->epsw & EPSW_nSL)
422 set_fs(seg);
423
424 tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000;
425 if (!tmp) {
426 if (!user_mode(regs))
427 printk(KERN_CRIT
428 "MISALIGN: %lx:"
429 " insn not move to/from memory %x\n",
430 regs->pc, opcode);
431 goto failed;
432 }
433
434 if (pop->params[0] & 0x80000000) {
435 /* move memory to register */
436 if (!misalignment_addr(registers, pop->params[0], opcode, disp,
437 &address, &postinc))
438 goto bad_addr_mode;
439
440 if (!misalignment_reg(registers, pop->params[1], opcode, disp,
441 &store))
442 goto bad_reg_mode;
443
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)
449 *postinc += 4;
450 } else if (strcmp(pop->name, "movhu") == 0) {
451 kdebug("FIXUP: movhu (%p),DARn\n", address);
452 data = 0;
453 if (copy_from_user(&data, (void *) address, 2) != 0)
454 goto transfer_failed;
455 if (pop->params[0] & 0x1000000)
456 *postinc += 2;
457 } else {
458 goto unsupported_instruction;
459 }
460
461 *store = data;
462 } else {
463 /* move register to memory */
464 if (!misalignment_reg(registers, pop->params[0], opcode, disp,
465 &store))
466 goto bad_reg_mode;
467
468 if (!misalignment_addr(registers, pop->params[1], opcode, disp,
469 &address, &postinc))
470 goto bad_addr_mode;
471
472 data = *store;
473
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)
479 *postinc += 4;
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)
486 *postinc += 2;
487 } else {
488 goto unsupported_instruction;
489 }
490 }
491
492 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz;
493 regs->pc += tmp >> 3;
494
495 set_fs(seg);
496 return;
497}
498
499/*
500 * determine the address that was being accessed
501 */
502static int misalignment_addr(unsigned long *registers, unsigned params,
503 unsigned opcode, unsigned disp,
504 void **_address, unsigned long **_postinc)
505{
506 unsigned long *postinc = NULL, address = 0, tmp;
507
508 params &= 0x7fffffff;
509
510 do {
511 switch (params & 0xff) {
512 case DM0:
513 postinc = &registers[Dreg_index[opcode & 0x03]];
514 address += *postinc;
515 break;
516 case DM1:
517 postinc = &registers[Dreg_index[opcode >> 2 & 0x0c]];
518 address += *postinc;
519 break;
520 case DM2:
521 postinc = &registers[Dreg_index[opcode >> 4 & 0x30]];
522 address += *postinc;
523 break;
524 case AM0:
525 postinc = &registers[Areg_index[opcode & 0x03]];
526 address += *postinc;
527 break;
528 case AM1:
529 postinc = &registers[Areg_index[opcode >> 2 & 0x0c]];
530 address += *postinc;
531 break;
532 case AM2:
533 postinc = &registers[Areg_index[opcode >> 4 & 0x30]];
534 address += *postinc;
535 break;
536 case RM0:
537 postinc = &registers[Rreg_index[opcode & 0x0f]];
538 address += *postinc;
539 break;
540 case RM1:
541 postinc = &registers[Rreg_index[opcode >> 2 & 0x0f]];
542 address += *postinc;
543 break;
544 case RM2:
545 postinc = &registers[Rreg_index[opcode >> 4 & 0x0f]];
546 address += *postinc;
547 break;
548 case RM4:
549 postinc = &registers[Rreg_index[opcode >> 8 & 0x0f]];
550 address += *postinc;
551 break;
552 case RM6:
553 postinc = &registers[Rreg_index[opcode >> 12 & 0x0f]];
554 address += *postinc;
555 break;
556 case RD0:
557 postinc = &registers[Rreg_index[disp & 0x0f]];
558 address += *postinc;
559 break;
560 case RD2:
561 postinc = &registers[Rreg_index[disp >> 4 & 0x0f]];
562 address += *postinc;
563 break;
564
565 case SD8:
566 case SIMM8:
567 address += (int32_t) (int8_t) (disp & 0xff);
568 break;
569 case SD16:
570 address += (int32_t) (int16_t) (disp & 0xffff);
571 break;
572 case SD24:
573 tmp = disp << 8;
574 asm("asr 8,%0" : "=r"(tmp) : "0"(tmp));
575 address += tmp;
576 break;
577 case SIMM4_2:
578 tmp = opcode >> 4 & 0x0f;
579 tmp <<= 28;
580 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
581 address += tmp;
582 break;
583 case IMM24:
584 address += disp & 0x00ffffff;
585 break;
586 case IMM32:
587 case IMM32_HIGH8:
588 address += disp;
589 break;
590 default:
591 return 0;
592 }
593 } while ((params >>= 8));
594
595 *_address = (void *) address;
596 *_postinc = postinc;
597 return 1;
598}
599
600/*
601 * determine the register that is acting as source/dest
602 */
603static int misalignment_reg(unsigned long *registers, unsigned params,
604 unsigned opcode, unsigned disp,
605 unsigned long **_register)
606{
607 params &= 0x7fffffff;
608
609 if (params & 0xffffff00)
610 return 0;
611
612 switch (params & 0xff) {
613 case DM0:
614 *_register = &registers[Dreg_index[opcode & 0x03]];
615 break;
616 case DM1:
617 *_register = &registers[Dreg_index[opcode >> 2 & 0x03]];
618 break;
619 case DM2:
620 *_register = &registers[Dreg_index[opcode >> 4 & 0x03]];
621 break;
622 case AM0:
623 *_register = &registers[Areg_index[opcode & 0x03]];
624 break;
625 case AM1:
626 *_register = &registers[Areg_index[opcode >> 2 & 0x03]];
627 break;
628 case AM2:
629 *_register = &registers[Areg_index[opcode >> 4 & 0x03]];
630 break;
631 case RM0:
632 *_register = &registers[Rreg_index[opcode & 0x0f]];
633 break;
634 case RM1:
635 *_register = &registers[Rreg_index[opcode >> 2 & 0x0f]];
636 break;
637 case RM2:
638 *_register = &registers[Rreg_index[opcode >> 4 & 0x0f]];
639 break;
640 case RM4:
641 *_register = &registers[Rreg_index[opcode >> 8 & 0x0f]];
642 break;
643 case RM6:
644 *_register = &registers[Rreg_index[opcode >> 12 & 0x0f]];
645 break;
646 case RD0:
647 *_register = &registers[Rreg_index[disp & 0x0f]];
648 break;
649 case RD2:
650 *_register = &registers[Rreg_index[disp >> 4 & 0x0f]];
651 break;
652 case SP:
653 *_register = &registers[REG_SP >> 2];
654 break;
655
656 default:
657 return 0;
658 }
659
660 return 1;
661}