1
2
3
4
5
6
7
8
9
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/init.h>
21#include <linux/delay.h>
22#include <linux/spinlock.h>
23#include <linux/interrupt.h>
24#include <linux/pci.h>
25#include <asm/processor.h>
26#include <asm/system.h>
27#include <asm/uaccess.h>
28#include <asm/io.h>
29#include <asm/atomic.h>
30#include <asm/smp.h>
31#include <asm/pgalloc.h>
32#include <asm/cpu-regs.h>
33#include <asm/busctl-regs.h>
34#include <asm/fpu.h>
35#include <asm/gdb-stub.h>
36#include <asm/asm-offsets.h>
37
38#if 0
39#define kdebug(FMT, ...) printk(KERN_DEBUG "MISALIGN: "FMT"\n", ##__VA_ARGS__)
40#else
41#define kdebug(FMT, ...) do {} while (0)
42#endif
43
44static int misalignment_addr(unsigned long *registers, unsigned long sp,
45 unsigned params, unsigned opcode,
46 unsigned long disp,
47 void **_address, unsigned long **_postinc,
48 unsigned long *_inc);
49
50static int misalignment_reg(unsigned long *registers, unsigned params,
51 unsigned opcode, unsigned long disp,
52 unsigned long **_register);
53
54static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode);
55
56static const unsigned Dreg_index[] = {
57 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
58};
59
60static const unsigned Areg_index[] = {
61 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2
62};
63
64static const unsigned Rreg_index[] = {
65 REG_E0 >> 2, REG_E1 >> 2, REG_E2 >> 2, REG_E3 >> 2,
66 REG_E4 >> 2, REG_E5 >> 2, REG_E6 >> 2, REG_E7 >> 2,
67 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2,
68 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
69};
70
71enum format_id {
72 FMT_S0,
73 FMT_S1,
74 FMT_S2,
75 FMT_S4,
76 FMT_D0,
77 FMT_D1,
78 FMT_D2,
79 FMT_D4,
80 FMT_D6,
81 FMT_D7,
82 FMT_D8,
83 FMT_D9,
84 FMT_D10,
85};
86
87static const struct {
88 u_int8_t opsz, dispsz;
89} format_tbl[16] = {
90 [FMT_S0] = { 8, 0 },
91 [FMT_S1] = { 8, 8 },
92 [FMT_S2] = { 8, 16 },
93 [FMT_S4] = { 8, 32 },
94 [FMT_D0] = { 16, 0 },
95 [FMT_D1] = { 16, 8 },
96 [FMT_D2] = { 16, 16 },
97 [FMT_D4] = { 16, 32 },
98 [FMT_D6] = { 24, 0 },
99 [FMT_D7] = { 24, 8 },
100 [FMT_D8] = { 24, 24 },
101 [FMT_D9] = { 24, 32 },
102 [FMT_D10] = { 32, 0 },
103};
104
105enum value_id {
106 DM0,
107 DM1,
108 DM2,
109 AM0,
110 AM1,
111 AM2,
112 RM0,
113 RM1,
114 RM2,
115 RM4,
116 RM6,
117
118 RD0,
119 RD2,
120
121 SP,
122
123 SD8,
124 SD16,
125 SD24,
126 SIMM4_2,
127 SIMM8,
128 IMM8,
129 IMM16,
130 IMM24,
131 IMM32,
132 IMM32_HIGH8,
133
134 IMM32_MEM,
135 IMM32_HIGH8_MEM,
136
137 DN0 = DM0,
138 DN1 = DM1,
139 DN2 = DM2,
140 AN0 = AM0,
141 AN1 = AM1,
142 AN2 = AM2,
143 RN0 = RM0,
144 RN1 = RM1,
145 RN2 = RM2,
146 RN4 = RM4,
147 RN6 = RM6,
148 DI = DM1,
149 RI = RM2,
150
151};
152
153struct mn10300_opcode {
154 const char name[8];
155 u_int32_t opcode;
156 u_int32_t opmask;
157 unsigned exclusion;
158
159 enum format_id format;
160
161 unsigned cpu_mask;
162#define AM33 330
163
164 unsigned params[2];
165#define MEM(ADDR) (0x80000000 | (ADDR))
166#define MEM2(ADDR1, ADDR2) (0x80000000 | (ADDR1) << 8 | (ADDR2))
167#define MEMINC(ADDR) (0x81000000 | (ADDR))
168#define MEMINC2(ADDR, INC) (0x81000000 | (ADDR) << 8 | (INC))
169};
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189static const struct mn10300_opcode mn10300_opcodes[] = {
190{ "mov", 0x4200, 0xf300, 0, FMT_S1, 0, {DM1, MEM2(IMM8, SP)}},
191{ "mov", 0x4300, 0xf300, 0, FMT_S1, 0, {AM1, MEM2(IMM8, SP)}},
192{ "mov", 0x5800, 0xfc00, 0, FMT_S1, 0, {MEM2(IMM8, SP), DN0}},
193{ "mov", 0x5c00, 0xfc00, 0, FMT_S1, 0, {MEM2(IMM8, SP), AN0}},
194{ "mov", 0x60, 0xf0, 0, FMT_S0, 0, {DM1, MEM(AN0)}},
195{ "mov", 0x70, 0xf0, 0, FMT_S0, 0, {MEM(AM0), DN1}},
196{ "mov", 0xf000, 0xfff0, 0, FMT_D0, 0, {MEM(AM0), AN1}},
197{ "mov", 0xf010, 0xfff0, 0, FMT_D0, 0, {AM1, MEM(AN0)}},
198{ "mov", 0xf300, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), DN2}},
199{ "mov", 0xf340, 0xffc0, 0, FMT_D0, 0, {DM2, MEM2(DI, AN0)}},
200{ "mov", 0xf380, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), AN2}},
201{ "mov", 0xf3c0, 0xffc0, 0, FMT_D0, 0, {AM2, MEM2(DI, AN0)}},
202{ "mov", 0xf80000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8, AM0), DN1}},
203{ "mov", 0xf81000, 0xfff000, 0, FMT_D1, 0, {DM1, MEM2(SD8, AN0)}},
204{ "mov", 0xf82000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8,AM0), AN1}},
205{ "mov", 0xf83000, 0xfff000, 0, FMT_D1, 0, {AM1, MEM2(SD8, AN0)}},
206{ "mov", 0xf90a00, 0xffff00, 0, FMT_D6, AM33, {MEM(RM0), RN2}},
207{ "mov", 0xf91a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEM(RN0)}},
208{ "mov", 0xf96a00, 0xffff00, 0x12, FMT_D6, AM33, {MEMINC(RM0), RN2}},
209{ "mov", 0xf97a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEMINC(RN0)}},
210{ "mov", 0xfa000000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), DN1}},
211{ "mov", 0xfa100000, 0xfff00000, 0, FMT_D2, 0, {DM1, MEM2(SD16, AN0)}},
212{ "mov", 0xfa200000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), AN1}},
213{ "mov", 0xfa300000, 0xfff00000, 0, FMT_D2, 0, {AM1, MEM2(SD16, AN0)}},
214{ "mov", 0xfa900000, 0xfff30000, 0, FMT_D2, 0, {AM1, MEM2(IMM16, SP)}},
215{ "mov", 0xfa910000, 0xfff30000, 0, FMT_D2, 0, {DM1, MEM2(IMM16, SP)}},
216{ "mov", 0xfab00000, 0xfffc0000, 0, FMT_D2, 0, {MEM2(IMM16, SP), AN0}},
217{ "mov", 0xfab40000, 0xfffc0000, 0, FMT_D2, 0, {MEM2(IMM16, SP), DN0}},
218{ "mov", 0xfb0a0000, 0xffff0000, 0, FMT_D7, AM33, {MEM2(SD8, RM0), RN2}},
219{ "mov", 0xfb1a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEM2(SD8, RN0)}},
220{ "mov", 0xfb6a0000, 0xffff0000, 0x22, FMT_D7, AM33, {MEMINC2 (RM0, SIMM8), RN2}},
221{ "mov", 0xfb7a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEMINC2 (RN0, SIMM8)}},
222{ "mov", 0xfb8a0000, 0xffff0f00, 0, FMT_D7, AM33, {MEM2(IMM8, SP), RN2}},
223{ "mov", 0xfb8e0000, 0xffff000f, 0, FMT_D7, AM33, {MEM2(RI, RM0), RD2}},
224{ "mov", 0xfb9a0000, 0xffff0f00, 0, FMT_D7, AM33, {RM2, MEM2(IMM8, SP)}},
225{ "mov", 0xfb9e0000, 0xffff000f, 0, FMT_D7, AM33, {RD2, MEM2(RI, RN0)}},
226{ "mov", 0xfc000000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), DN1}},
227{ "mov", 0xfc100000, 0xfff00000, 0, FMT_D4, 0, {DM1, MEM2(IMM32,AN0)}},
228{ "mov", 0xfc200000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), AN1}},
229{ "mov", 0xfc300000, 0xfff00000, 0, FMT_D4, 0, {AM1, MEM2(IMM32,AN0)}},
230{ "mov", 0xfc800000, 0xfff30000, 0, FMT_D4, 0, {AM1, MEM(IMM32_MEM)}},
231{ "mov", 0xfc810000, 0xfff30000, 0, FMT_D4, 0, {DM1, MEM(IMM32_MEM)}},
232{ "mov", 0xfc900000, 0xfff30000, 0, FMT_D4, 0, {AM1, MEM2(IMM32, SP)}},
233{ "mov", 0xfc910000, 0xfff30000, 0, FMT_D4, 0, {DM1, MEM2(IMM32, SP)}},
234{ "mov", 0xfca00000, 0xfffc0000, 0, FMT_D4, 0, {MEM(IMM32_MEM), AN0}},
235{ "mov", 0xfca40000, 0xfffc0000, 0, FMT_D4, 0, {MEM(IMM32_MEM), DN0}},
236{ "mov", 0xfcb00000, 0xfffc0000, 0, FMT_D4, 0, {MEM2(IMM32, SP), AN0}},
237{ "mov", 0xfcb40000, 0xfffc0000, 0, FMT_D4, 0, {MEM2(IMM32, SP), DN0}},
238{ "mov", 0xfd0a0000, 0xffff0000, 0, FMT_D8, AM33, {MEM2(SD24, RM0), RN2}},
239{ "mov", 0xfd1a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEM2(SD24, RN0)}},
240{ "mov", 0xfd6a0000, 0xffff0000, 0x22, FMT_D8, AM33, {MEMINC2 (RM0, IMM24), RN2}},
241{ "mov", 0xfd7a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEMINC2 (RN0, IMM24)}},
242{ "mov", 0xfd8a0000, 0xffff0f00, 0, FMT_D8, AM33, {MEM2(IMM24, SP), RN2}},
243{ "mov", 0xfd9a0000, 0xffff0f00, 0, FMT_D8, AM33, {RM2, MEM2(IMM24, SP)}},
244{ "mov", 0xfe0a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}},
245{ "mov", 0xfe0a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}},
246{ "mov", 0xfe0e0000, 0xffff0f00, 0, FMT_D9, AM33, {MEM(IMM32_HIGH8_MEM), RN2}},
247{ "mov", 0xfe1a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}},
248{ "mov", 0xfe1a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}},
249{ "mov", 0xfe1e0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM(IMM32_HIGH8_MEM)}},
250{ "mov", 0xfe6a0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
251{ "mov", 0xfe7a0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
252{ "mov", 0xfe8a0000, 0xffff0f00, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8, SP), RN2}},
253{ "mov", 0xfe9a0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, SP)}},
254
255{ "movhu", 0xf060, 0xfff0, 0, FMT_D0, 0, {MEM(AM0), DN1}},
256{ "movhu", 0xf070, 0xfff0, 0, FMT_D0, 0, {DM1, MEM(AN0)}},
257{ "movhu", 0xf480, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), DN2}},
258{ "movhu", 0xf4c0, 0xffc0, 0, FMT_D0, 0, {DM2, MEM2(DI, AN0)}},
259{ "movhu", 0xf86000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8, AM0), DN1}},
260{ "movhu", 0xf87000, 0xfff000, 0, FMT_D1, 0, {DM1, MEM2(SD8, AN0)}},
261{ "movhu", 0xf89300, 0xfff300, 0, FMT_D1, 0, {DM1, MEM2(IMM8, SP)}},
262{ "movhu", 0xf8bc00, 0xfffc00, 0, FMT_D1, 0, {MEM2(IMM8, SP), DN0}},
263{ "movhu", 0xf94a00, 0xffff00, 0, FMT_D6, AM33, {MEM(RM0), RN2}},
264{ "movhu", 0xf95a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEM(RN0)}},
265{ "movhu", 0xf9ea00, 0xffff00, 0x12, FMT_D6, AM33, {MEMINC(RM0), RN2}},
266{ "movhu", 0xf9fa00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEMINC(RN0)}},
267{ "movhu", 0xfa600000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), DN1}},
268{ "movhu", 0xfa700000, 0xfff00000, 0, FMT_D2, 0, {DM1, MEM2(SD16, AN0)}},
269{ "movhu", 0xfa930000, 0xfff30000, 0, FMT_D2, 0, {DM1, MEM2(IMM16, SP)}},
270{ "movhu", 0xfabc0000, 0xfffc0000, 0, FMT_D2, 0, {MEM2(IMM16, SP), DN0}},
271{ "movhu", 0xfb4a0000, 0xffff0000, 0, FMT_D7, AM33, {MEM2(SD8, RM0), RN2}},
272{ "movhu", 0xfb5a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEM2(SD8, RN0)}},
273{ "movhu", 0xfbca0000, 0xffff0f00, 0, FMT_D7, AM33, {MEM2(IMM8, SP), RN2}},
274{ "movhu", 0xfbce0000, 0xffff000f, 0, FMT_D7, AM33, {MEM2(RI, RM0), RD2}},
275{ "movhu", 0xfbda0000, 0xffff0f00, 0, FMT_D7, AM33, {RM2, MEM2(IMM8, SP)}},
276{ "movhu", 0xfbde0000, 0xffff000f, 0, FMT_D7, AM33, {RD2, MEM2(RI, RN0)}},
277{ "movhu", 0xfbea0000, 0xffff0000, 0x22, FMT_D7, AM33, {MEMINC2 (RM0, SIMM8), RN2}},
278{ "movhu", 0xfbfa0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEMINC2 (RN0, SIMM8)}},
279{ "movhu", 0xfc600000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), DN1}},
280{ "movhu", 0xfc700000, 0xfff00000, 0, FMT_D4, 0, {DM1, MEM2(IMM32,AN0)}},
281{ "movhu", 0xfc830000, 0xfff30000, 0, FMT_D4, 0, {DM1, MEM(IMM32_MEM)}},
282{ "movhu", 0xfc930000, 0xfff30000, 0, FMT_D4, 0, {DM1, MEM2(IMM32, SP)}},
283{ "movhu", 0xfcac0000, 0xfffc0000, 0, FMT_D4, 0, {MEM(IMM32_MEM), DN0}},
284{ "movhu", 0xfcbc0000, 0xfffc0000, 0, FMT_D4, 0, {MEM2(IMM32, SP), DN0}},
285{ "movhu", 0xfd4a0000, 0xffff0000, 0, FMT_D8, AM33, {MEM2(SD24, RM0), RN2}},
286{ "movhu", 0xfd5a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEM2(SD24, RN0)}},
287{ "movhu", 0xfdca0000, 0xffff0f00, 0, FMT_D8, AM33, {MEM2(IMM24, SP), RN2}},
288{ "movhu", 0xfdda0000, 0xffff0f00, 0, FMT_D8, AM33, {RM2, MEM2(IMM24, SP)}},
289{ "movhu", 0xfdea0000, 0xffff0000, 0x22, FMT_D8, AM33, {MEMINC2 (RM0, IMM24), RN2}},
290{ "movhu", 0xfdfa0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEMINC2 (RN0, IMM24)}},
291{ "movhu", 0xfe4a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}},
292{ "movhu", 0xfe4e0000, 0xffff0f00, 0, FMT_D9, AM33, {MEM(IMM32_HIGH8_MEM), RN2}},
293{ "movhu", 0xfe5a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}},
294{ "movhu", 0xfe5e0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM(IMM32_HIGH8_MEM)}},
295{ "movhu", 0xfeca0000, 0xffff0f00, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8, SP), RN2}},
296{ "movhu", 0xfeda0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, SP)}},
297{ "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
298{ "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
299
300{ "mov_llt", 0xf7e00000, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
301{ "mov_lgt", 0xf7e00001, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
302{ "mov_lge", 0xf7e00002, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
303{ "mov_lle", 0xf7e00003, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
304{ "mov_lcs", 0xf7e00004, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
305{ "mov_lhi", 0xf7e00005, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
306{ "mov_lcc", 0xf7e00006, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
307{ "mov_lls", 0xf7e00007, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
308{ "mov_leq", 0xf7e00008, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
309{ "mov_lne", 0xf7e00009, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
310{ "mov_lra", 0xf7e0000a, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
311
312{ "", 0, 0, 0, 0, 0, {0}},
313};
314
315
316
317
318asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
319{
320 const struct exception_table_entry *fixup;
321 const struct mn10300_opcode *pop;
322 unsigned long *registers = (unsigned long *) regs;
323 unsigned long data, *store, *postinc, disp, inc, sp;
324 mm_segment_t seg;
325 siginfo_t info;
326 uint32_t opcode, noc, xo, xm;
327 uint8_t *pc, byte, datasz;
328 void *address;
329 unsigned tmp, npop, dispsz, loop;
330
331
332 if (user_mode(regs))
333 goto bus_error;
334
335 sp = (unsigned long) regs + sizeof(*regs);
336
337 kdebug("==>misalignment({pc=%lx,sp=%lx})", regs->pc, sp);
338
339 if (regs->epsw & EPSW_IE)
340 asm volatile("or %0,epsw" : : "i"(EPSW_IE));
341
342 seg = get_fs();
343 set_fs(KERNEL_DS);
344
345 fixup = search_exception_tables(regs->pc);
346
347
348 pc = (u_int8_t *) regs->pc;
349
350 if (__get_user(byte, pc) != 0)
351 goto fetch_error;
352 opcode = byte;
353 noc = 8;
354
355 for (pop = mn10300_opcodes; pop->name[0]; pop++) {
356 npop = ilog2(pop->opcode | pop->opmask);
357 if (npop <= 0 || npop > 31)
358 continue;
359 npop = (npop + 8) & ~7;
360
361 got_more_bits:
362 if (npop == noc) {
363 if ((opcode & pop->opmask) == pop->opcode)
364 goto found_opcode;
365 } else if (npop > noc) {
366 xo = pop->opcode >> (npop - noc);
367 xm = pop->opmask >> (npop - noc);
368
369 if ((opcode & xm) != xo)
370 continue;
371
372
373
374 pc++;
375 if (__get_user(byte, pc) != 0)
376 goto fetch_error;
377 opcode = opcode << 8 | byte;
378 noc += 8;
379 goto got_more_bits;
380 } else {
381
382
383
384 continue;
385 }
386 }
387
388
389 printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n",
390 regs->pc, opcode);
391
392failed:
393 set_fs(seg);
394 if (die_if_no_fixup("misalignment error", regs, code))
395 return;
396
397bus_error:
398 info.si_signo = SIGBUS;
399 info.si_errno = 0;
400 info.si_code = BUS_ADRALN;
401 info.si_addr = (void *) regs->pc;
402 force_sig_info(SIGBUS, &info, current);
403 return;
404
405
406fetch_error:
407 printk(KERN_CRIT
408 "MISALIGN: %p: fault whilst reading instruction data\n",
409 pc);
410 goto failed;
411
412bad_addr_mode:
413 printk(KERN_CRIT
414 "MISALIGN: %lx: unsupported addressing mode %x\n",
415 regs->pc, opcode);
416 goto failed;
417
418bad_reg_mode:
419 printk(KERN_CRIT
420 "MISALIGN: %lx: unsupported register mode %x\n",
421 regs->pc, opcode);
422 goto failed;
423
424unsupported_instruction:
425 printk(KERN_CRIT
426 "MISALIGN: %lx: unsupported instruction %x (%s)\n",
427 regs->pc, opcode, pop->name);
428 goto failed;
429
430transfer_failed:
431 set_fs(seg);
432 if (fixup) {
433 regs->pc = fixup->fixup;
434 return;
435 }
436 if (die_if_no_fixup("misalignment fixup", regs, code))
437 return;
438
439 info.si_signo = SIGSEGV;
440 info.si_errno = 0;
441 info.si_code = 0;
442 info.si_addr = (void *) regs->pc;
443 force_sig_info(SIGSEGV, &info, current);
444 return;
445
446
447found_opcode:
448 kdebug("%lx: %x==%x { %x, %x }",
449 regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]);
450
451 tmp = format_tbl[pop->format].opsz;
452 if (tmp > noc)
453 BUG();
454
455 if (tmp < noc) {
456 tmp = noc - tmp;
457 opcode >>= tmp;
458 pc -= tmp >> 3;
459 }
460
461
462 disp = 0;
463 dispsz = format_tbl[pop->format].dispsz;
464 for (loop = 0; loop < dispsz; loop += 8) {
465 pc++;
466 if (__get_user(byte, pc) != 0)
467 goto fetch_error;
468 disp |= byte << loop;
469 kdebug("{%p} disp[%02x]=%02x", pc, loop, byte);
470 }
471
472 kdebug("disp=%lx", disp);
473
474 set_fs(KERNEL_XDS);
475 if (fixup)
476 set_fs(seg);
477
478 tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000;
479 if (!tmp) {
480 printk(KERN_CRIT
481 "MISALIGN: %lx: insn not move to/from memory %x\n",
482 regs->pc, opcode);
483 goto failed;
484 }
485
486
487 if (pop->name[3] == 0 ||
488 pop->name[4] == 'l')
489 inc = datasz = 4;
490 else if (pop->name[3] == 'h')
491 inc = datasz = 2;
492 else
493 goto unsupported_instruction;
494
495 if (pop->params[0] & 0x80000000) {
496
497 if (!misalignment_addr(registers, sp,
498 pop->params[0], opcode, disp,
499 &address, &postinc, &inc))
500 goto bad_addr_mode;
501
502 if (!misalignment_reg(registers, pop->params[1], opcode, disp,
503 &store))
504 goto bad_reg_mode;
505
506 kdebug("mov%u (%p),DARn", datasz, address);
507 if (copy_from_user(&data, (void *) address, datasz) != 0)
508 goto transfer_failed;
509 if (pop->params[0] & 0x1000000) {
510 kdebug("inc=%lx", inc);
511 *postinc += inc;
512 }
513
514 *store = data;
515 kdebug("loaded %lx", data);
516 } else {
517
518 if (!misalignment_reg(registers, pop->params[0], opcode, disp,
519 &store))
520 goto bad_reg_mode;
521
522 if (!misalignment_addr(registers, sp,
523 pop->params[1], opcode, disp,
524 &address, &postinc, &inc))
525 goto bad_addr_mode;
526
527 data = *store;
528
529 kdebug("mov%u %lx,(%p)", datasz, data, address);
530 if (copy_to_user((void *) address, &data, datasz) != 0)
531 goto transfer_failed;
532 if (pop->params[1] & 0x1000000)
533 *postinc += inc;
534 }
535
536 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz;
537 regs->pc += tmp >> 3;
538
539
540
541 if (pop->format == FMT_D10)
542 misalignment_MOV_Lcc(regs, opcode);
543
544 set_fs(seg);
545}
546
547
548
549
550static int misalignment_addr(unsigned long *registers, unsigned long sp,
551 unsigned params, unsigned opcode,
552 unsigned long disp,
553 void **_address, unsigned long **_postinc,
554 unsigned long *_inc)
555{
556 unsigned long *postinc = NULL, address = 0, tmp;
557
558 if (!(params & 0x1000000)) {
559 kdebug("noinc");
560 *_inc = 0;
561 _inc = NULL;
562 }
563
564 params &= 0x00ffffff;
565
566 do {
567 switch (params & 0xff) {
568 case DM0:
569 postinc = ®isters[Dreg_index[opcode & 0x03]];
570 address += *postinc;
571 break;
572 case DM1:
573 postinc = ®isters[Dreg_index[opcode >> 2 & 0x03]];
574 address += *postinc;
575 break;
576 case DM2:
577 postinc = ®isters[Dreg_index[opcode >> 4 & 0x03]];
578 address += *postinc;
579 break;
580 case AM0:
581 postinc = ®isters[Areg_index[opcode & 0x03]];
582 address += *postinc;
583 break;
584 case AM1:
585 postinc = ®isters[Areg_index[opcode >> 2 & 0x03]];
586 address += *postinc;
587 break;
588 case AM2:
589 postinc = ®isters[Areg_index[opcode >> 4 & 0x03]];
590 address += *postinc;
591 break;
592 case RM0:
593 postinc = ®isters[Rreg_index[opcode & 0x0f]];
594 address += *postinc;
595 break;
596 case RM1:
597 postinc = ®isters[Rreg_index[opcode >> 2 & 0x0f]];
598 address += *postinc;
599 break;
600 case RM2:
601 postinc = ®isters[Rreg_index[opcode >> 4 & 0x0f]];
602 address += *postinc;
603 break;
604 case RM4:
605 postinc = ®isters[Rreg_index[opcode >> 8 & 0x0f]];
606 address += *postinc;
607 break;
608 case RM6:
609 postinc = ®isters[Rreg_index[opcode >> 12 & 0x0f]];
610 address += *postinc;
611 break;
612 case RD0:
613 postinc = ®isters[Rreg_index[disp & 0x0f]];
614 address += *postinc;
615 break;
616 case RD2:
617 postinc = ®isters[Rreg_index[disp >> 4 & 0x0f]];
618 address += *postinc;
619 break;
620 case SP:
621 address += sp;
622 break;
623
624
625
626
627 case SD8:
628 case SIMM8:
629 disp = (long) (int8_t) (disp & 0xff);
630 goto displace_or_inc;
631 case SD16:
632 disp = (long) (int16_t) (disp & 0xffff);
633 goto displace_or_inc;
634 case SD24:
635 tmp = disp << 8;
636 asm("asr 8,%0" : "=r"(tmp) : "0"(tmp));
637 disp = (long) tmp;
638 goto displace_or_inc;
639 case SIMM4_2:
640 tmp = opcode >> 4 & 0x0f;
641 tmp <<= 28;
642 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
643 disp = (long) tmp;
644 goto displace_or_inc;
645 case IMM8:
646 disp &= 0x000000ff;
647 goto displace_or_inc;
648 case IMM16:
649 disp &= 0x0000ffff;
650 goto displace_or_inc;
651 case IMM24:
652 disp &= 0x00ffffff;
653 goto displace_or_inc;
654 case IMM32:
655 case IMM32_MEM:
656 case IMM32_HIGH8:
657 case IMM32_HIGH8_MEM:
658 displace_or_inc:
659 kdebug("%s %lx", _inc ? "incr" : "disp", disp);
660 if (!_inc)
661 address += disp;
662 else
663 *_inc = disp;
664 break;
665 default:
666 BUG();
667 return 0;
668 }
669 } while ((params >>= 8));
670
671 *_address = (void *) address;
672 *_postinc = postinc;
673 return 1;
674}
675
676
677
678
679static int misalignment_reg(unsigned long *registers, unsigned params,
680 unsigned opcode, unsigned long disp,
681 unsigned long **_register)
682{
683 params &= 0x7fffffff;
684
685 if (params & 0xffffff00)
686 return 0;
687
688 switch (params & 0xff) {
689 case DM0:
690 *_register = ®isters[Dreg_index[opcode & 0x03]];
691 break;
692 case DM1:
693 *_register = ®isters[Dreg_index[opcode >> 2 & 0x03]];
694 break;
695 case DM2:
696 *_register = ®isters[Dreg_index[opcode >> 4 & 0x03]];
697 break;
698 case AM0:
699 *_register = ®isters[Areg_index[opcode & 0x03]];
700 break;
701 case AM1:
702 *_register = ®isters[Areg_index[opcode >> 2 & 0x03]];
703 break;
704 case AM2:
705 *_register = ®isters[Areg_index[opcode >> 4 & 0x03]];
706 break;
707 case RM0:
708 *_register = ®isters[Rreg_index[opcode & 0x0f]];
709 break;
710 case RM1:
711 *_register = ®isters[Rreg_index[opcode >> 2 & 0x0f]];
712 break;
713 case RM2:
714 *_register = ®isters[Rreg_index[opcode >> 4 & 0x0f]];
715 break;
716 case RM4:
717 *_register = ®isters[Rreg_index[opcode >> 8 & 0x0f]];
718 break;
719 case RM6:
720 *_register = ®isters[Rreg_index[opcode >> 12 & 0x0f]];
721 break;
722 case RD0:
723 *_register = ®isters[Rreg_index[disp & 0x0f]];
724 break;
725 case RD2:
726 *_register = ®isters[Rreg_index[disp >> 4 & 0x0f]];
727 break;
728 case SP:
729 *_register = ®isters[REG_SP >> 2];
730 break;
731
732 default:
733 BUG();
734 return 0;
735 }
736
737 return 1;
738}
739
740
741
742
743static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode)
744{
745 unsigned long epsw = regs->epsw;
746 unsigned long NxorV;
747
748 kdebug("MOV_Lcc %x [flags=%lx]", opcode, epsw & 0xf);
749
750
751 NxorV = ((epsw >> 3) ^ epsw >> 1) & 1;
752
753 switch (opcode & 0xf) {
754 case 0x0:
755 if (NxorV)
756 goto take_the_loop;
757 return;
758 case 0x1:
759 if (!((epsw & EPSW_FLAG_Z) | NxorV))
760 goto take_the_loop;
761 return;
762 case 0x2:
763 if (!NxorV)
764 goto take_the_loop;
765 return;
766 case 0x3:
767 if ((epsw & EPSW_FLAG_Z) | NxorV)
768 goto take_the_loop;
769 return;
770
771 case 0x4:
772 if (epsw & EPSW_FLAG_C)
773 goto take_the_loop;
774 return;
775 case 0x5:
776 if (!(epsw & (EPSW_FLAG_C | EPSW_FLAG_Z)))
777 goto take_the_loop;
778 return;
779 case 0x6:
780 if (!(epsw & EPSW_FLAG_C))
781 goto take_the_loop;
782 return;
783 case 0x7:
784 if (epsw & (EPSW_FLAG_C | EPSW_FLAG_Z))
785 goto take_the_loop;
786 return;
787
788 case 0x8:
789 if (epsw & EPSW_FLAG_Z)
790 goto take_the_loop;
791 return;
792 case 0x9:
793 if (!(epsw & EPSW_FLAG_Z))
794 goto take_the_loop;
795 return;
796 case 0xa:
797 goto take_the_loop;
798
799 default:
800 BUG();
801 }
802
803take_the_loop:
804
805 kdebug("loop LAR=%lx", regs->lar);
806 regs->pc = regs->lar - 4;
807}
808
809
810
811
812#ifdef CONFIG_TEST_MISALIGNMENT_HANDLER
813static u8 __initdata testbuf[512] __attribute__((aligned(16))) = {
814 [257] = 0x11,
815 [258] = 0x22,
816 [259] = 0x33,
817 [260] = 0x44,
818};
819
820#define ASSERTCMP(X, OP, Y) \
821do { \
822 if (unlikely(!((X) OP (Y)))) { \
823 printk(KERN_ERR "\n"); \
824 printk(KERN_ERR "MISALIGN: Assertion failed at line %u\n", \
825 __LINE__); \
826 printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n", \
827 (unsigned long)(X), (unsigned long)(Y)); \
828 BUG(); \
829 } \
830} while(0)
831
832static int __init test_misalignment(void)
833{
834 register void *r asm("e0");
835 register u32 y asm("e1");
836 void *p = testbuf, *q;
837 u32 tmp, tmp2, x;
838
839 printk(KERN_NOTICE "==>test_misalignment() [testbuf=%p]\n", p);
840 p++;
841
842 printk(KERN_NOTICE "___ MOV (Am),Dn ___\n");
843 q = p + 256;
844 asm volatile("mov (%0),%1" : "+a"(q), "=d"(x));
845 ASSERTCMP(q, ==, p + 256);
846 ASSERTCMP(x, ==, 0x44332211);
847
848 printk(KERN_NOTICE "___ MOV (256,Am),Dn ___\n");
849 q = p;
850 asm volatile("mov (256,%0),%1" : "+a"(q), "=d"(x));
851 ASSERTCMP(q, ==, p);
852 ASSERTCMP(x, ==, 0x44332211);
853
854 printk(KERN_NOTICE "___ MOV (Di,Am),Dn ___\n");
855 tmp = 256;
856 q = p;
857 asm volatile("mov (%2,%0),%1" : "+a"(q), "=d"(x), "+d"(tmp));
858 ASSERTCMP(q, ==, p);
859 ASSERTCMP(x, ==, 0x44332211);
860 ASSERTCMP(tmp, ==, 256);
861
862 printk(KERN_NOTICE "___ MOV (256,Rm),Rn ___\n");
863 r = p;
864 asm volatile("mov (256,%0),%1" : "+r"(r), "=r"(y));
865 ASSERTCMP(r, ==, p);
866 ASSERTCMP(y, ==, 0x44332211);
867
868 printk(KERN_NOTICE "___ MOV (Rm+),Rn ___\n");
869 r = p + 256;
870 asm volatile("mov (%0+),%1" : "+r"(r), "=r"(y));
871 ASSERTCMP(r, ==, p + 256 + 4);
872 ASSERTCMP(y, ==, 0x44332211);
873
874 printk(KERN_NOTICE "___ MOV (Rm+,8),Rn ___\n");
875 r = p + 256;
876 asm volatile("mov (%0+,8),%1" : "+r"(r), "=r"(y));
877 ASSERTCMP(r, ==, p + 256 + 8);
878 ASSERTCMP(y, ==, 0x44332211);
879
880 printk(KERN_NOTICE "___ MOV (7,SP),Rn ___\n");
881 asm volatile(
882 "add -16,sp \n"
883 "mov +0x11,%0 \n"
884 "movbu %0,(7,sp) \n"
885 "mov +0x22,%0 \n"
886 "movbu %0,(8,sp) \n"
887 "mov +0x33,%0 \n"
888 "movbu %0,(9,sp) \n"
889 "mov +0x44,%0 \n"
890 "movbu %0,(10,sp) \n"
891 "mov (7,sp),%1 \n"
892 "add +16,sp \n"
893 : "+a"(q), "=d"(x));
894 ASSERTCMP(x, ==, 0x44332211);
895
896 printk(KERN_NOTICE "___ MOV (259,SP),Rn ___\n");
897 asm volatile(
898 "add -264,sp \n"
899 "mov +0x11,%0 \n"
900 "movbu %0,(259,sp) \n"
901 "mov +0x22,%0 \n"
902 "movbu %0,(260,sp) \n"
903 "mov +0x33,%0 \n"
904 "movbu %0,(261,sp) \n"
905 "mov +0x55,%0 \n"
906 "movbu %0,(262,sp) \n"
907 "mov (259,sp),%1 \n"
908 "add +264,sp \n"
909 : "+d"(tmp), "=d"(x));
910 ASSERTCMP(x, ==, 0x55332211);
911
912 printk(KERN_NOTICE "___ MOV (260,SP),Rn ___\n");
913 asm volatile(
914 "add -264,sp \n"
915 "mov +0x11,%0 \n"
916 "movbu %0,(260,sp) \n"
917 "mov +0x22,%0 \n"
918 "movbu %0,(261,sp) \n"
919 "mov +0x33,%0 \n"
920 "movbu %0,(262,sp) \n"
921 "mov +0x55,%0 \n"
922 "movbu %0,(263,sp) \n"
923 "mov (260,sp),%1 \n"
924 "add +264,sp \n"
925 : "+d"(tmp), "=d"(x));
926 ASSERTCMP(x, ==, 0x55332211);
927
928
929 printk(KERN_NOTICE "___ MOV_LNE ___\n");
930 tmp = 1;
931 tmp2 = 2;
932 q = p + 256;
933 asm volatile(
934 "setlb \n"
935 "mov %2,%3 \n"
936 "mov %1,%2 \n"
937 "cmp +0,%1 \n"
938 "mov_lne (%0+,4),%1"
939 : "+r"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
940 :
941 : "cc");
942 ASSERTCMP(q, ==, p + 256 + 12);
943 ASSERTCMP(x, ==, 0x44332211);
944
945 printk(KERN_NOTICE "___ MOV in SETLB ___\n");
946 tmp = 1;
947 tmp2 = 2;
948 q = p + 256;
949 asm volatile(
950 "setlb \n"
951 "mov %1,%3 \n"
952 "mov (%0+),%1 \n"
953 "cmp +0,%1 \n"
954 "lne "
955 : "+a"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
956 :
957 : "cc");
958
959 ASSERTCMP(q, ==, p + 256 + 8);
960 ASSERTCMP(x, ==, 0x44332211);
961
962 printk(KERN_NOTICE "<==test_misalignment()\n");
963 return 0;
964}
965
966arch_initcall(test_misalignment);
967
968#endif
969