misalignment.c revision b308bf3be1f75207c307eea9ada90e0b76194911
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
45static int misalignment_addr(unsigned long *registers, unsigned params,
46			     unsigned opcode, unsigned long disp,
47			     void **_address, unsigned long **_postinc);
48
49static int misalignment_reg(unsigned long *registers, unsigned params,
50			    unsigned opcode, unsigned long disp,
51			    unsigned long **_register);
52
53static const unsigned Dreg_index[] = {
54	REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
55};
56
57static const unsigned Areg_index[] = {
58	REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2
59};
60
61static 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
68enum 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
83static 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
100enum 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
148struct 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*/
184static 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 */
302asmlinkage 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
374failed:
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 */
387fetch_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
394bad_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
401bad_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
408unsupported_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
415transfer_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 */
432found_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 */
540static 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 */
646static 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
710static 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)						\
718do {									\
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
729static 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
863arch_initcall(test_misalignment);
864
865#endif /* CONFIG_TEST_MISALIGNMENT_HANDLER */
866