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 <linux/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 BUG_ON(tmp > noc);
453
454 if (tmp < noc) {
455 tmp = noc - tmp;
456 opcode >>= tmp;
457 pc -= tmp >> 3;
458 }
459
460
461 disp = 0;
462 dispsz = format_tbl[pop->format].dispsz;
463 for (loop = 0; loop < dispsz; loop += 8) {
464 pc++;
465 if (__get_user(byte, pc) != 0)
466 goto fetch_error;
467 disp |= byte << loop;
468 kdebug("{%p} disp[%02x]=%02x", pc, loop, byte);
469 }
470
471 kdebug("disp=%lx", disp);
472
473 set_fs(KERNEL_XDS);
474 if (fixup)
475 set_fs(seg);
476
477 tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000;
478 if (!tmp) {
479 printk(KERN_CRIT
480 "MISALIGN: %lx: insn not move to/from memory %x\n",
481 regs->pc, opcode);
482 goto failed;
483 }
484
485
486 if (pop->name[3] == 0 ||
487 pop->name[4] == 'l')
488 inc = datasz = 4;
489 else if (pop->name[3] == 'h')
490 inc = datasz = 2;
491 else
492 goto unsupported_instruction;
493
494 if (pop->params[0] & 0x80000000) {
495
496 if (!misalignment_addr(registers, sp,
497 pop->params[0], opcode, disp,
498 &address, &postinc, &inc))
499 goto bad_addr_mode;
500
501 if (!misalignment_reg(registers, pop->params[1], opcode, disp,
502 &store))
503 goto bad_reg_mode;
504
505 kdebug("mov%u (%p),DARn", datasz, address);
506 if (copy_from_user(&data, (void *) address, datasz) != 0)
507 goto transfer_failed;
508 if (pop->params[0] & 0x1000000) {
509 kdebug("inc=%lx", inc);
510 *postinc += inc;
511 }
512
513 *store = data;
514 kdebug("loaded %lx", data);
515 } else {
516
517 if (!misalignment_reg(registers, pop->params[0], opcode, disp,
518 &store))
519 goto bad_reg_mode;
520
521 if (!misalignment_addr(registers, sp,
522 pop->params[1], opcode, disp,
523 &address, &postinc, &inc))
524 goto bad_addr_mode;
525
526 data = *store;
527
528 kdebug("mov%u %lx,(%p)", datasz, data, address);
529 if (copy_to_user((void *) address, &data, datasz) != 0)
530 goto transfer_failed;
531 if (pop->params[1] & 0x1000000)
532 *postinc += inc;
533 }
534
535 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz;
536 regs->pc += tmp >> 3;
537
538
539
540 if (pop->format == FMT_D10)
541 misalignment_MOV_Lcc(regs, opcode);
542
543 set_fs(seg);
544}
545
546
547
548
549static int misalignment_addr(unsigned long *registers, unsigned long sp,
550 unsigned params, unsigned opcode,
551 unsigned long disp,
552 void **_address, unsigned long **_postinc,
553 unsigned long *_inc)
554{
555 unsigned long *postinc = NULL, address = 0, tmp;
556
557 if (!(params & 0x1000000)) {
558 kdebug("noinc");
559 *_inc = 0;
560 _inc = NULL;
561 }
562
563 params &= 0x00ffffff;
564
565 do {
566 switch (params & 0xff) {
567 case DM0:
568 postinc = ®isters[Dreg_index[opcode & 0x03]];
569 address += *postinc;
570 break;
571 case DM1:
572 postinc = ®isters[Dreg_index[opcode >> 2 & 0x03]];
573 address += *postinc;
574 break;
575 case DM2:
576 postinc = ®isters[Dreg_index[opcode >> 4 & 0x03]];
577 address += *postinc;
578 break;
579 case AM0:
580 postinc = ®isters[Areg_index[opcode & 0x03]];
581 address += *postinc;
582 break;
583 case AM1:
584 postinc = ®isters[Areg_index[opcode >> 2 & 0x03]];
585 address += *postinc;
586 break;
587 case AM2:
588 postinc = ®isters[Areg_index[opcode >> 4 & 0x03]];
589 address += *postinc;
590 break;
591 case RM0:
592 postinc = ®isters[Rreg_index[opcode & 0x0f]];
593 address += *postinc;
594 break;
595 case RM1:
596 postinc = ®isters[Rreg_index[opcode >> 2 & 0x0f]];
597 address += *postinc;
598 break;
599 case RM2:
600 postinc = ®isters[Rreg_index[opcode >> 4 & 0x0f]];
601 address += *postinc;
602 break;
603 case RM4:
604 postinc = ®isters[Rreg_index[opcode >> 8 & 0x0f]];
605 address += *postinc;
606 break;
607 case RM6:
608 postinc = ®isters[Rreg_index[opcode >> 12 & 0x0f]];
609 address += *postinc;
610 break;
611 case RD0:
612 postinc = ®isters[Rreg_index[disp & 0x0f]];
613 address += *postinc;
614 break;
615 case RD2:
616 postinc = ®isters[Rreg_index[disp >> 4 & 0x0f]];
617 address += *postinc;
618 break;
619 case SP:
620 address += sp;
621 break;
622
623
624
625
626 case SD8:
627 case SIMM8:
628 disp = (long) (int8_t) (disp & 0xff);
629 goto displace_or_inc;
630 case SD16:
631 disp = (long) (int16_t) (disp & 0xffff);
632 goto displace_or_inc;
633 case SD24:
634 tmp = disp << 8;
635 asm("asr 8,%0" : "=r"(tmp) : "0"(tmp) : "cc");
636 disp = (long) tmp;
637 goto displace_or_inc;
638 case SIMM4_2:
639 tmp = opcode >> 4 & 0x0f;
640 tmp <<= 28;
641 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp) : "cc");
642 disp = (long) tmp;
643 goto displace_or_inc;
644 case IMM8:
645 disp &= 0x000000ff;
646 goto displace_or_inc;
647 case IMM16:
648 disp &= 0x0000ffff;
649 goto displace_or_inc;
650 case IMM24:
651 disp &= 0x00ffffff;
652 goto displace_or_inc;
653 case IMM32:
654 case IMM32_MEM:
655 case IMM32_HIGH8:
656 case IMM32_HIGH8_MEM:
657 displace_or_inc:
658 kdebug("%s %lx", _inc ? "incr" : "disp", disp);
659 if (!_inc)
660 address += disp;
661 else
662 *_inc = disp;
663 break;
664 default:
665 BUG();
666 return 0;
667 }
668 } while ((params >>= 8));
669
670 *_address = (void *) address;
671 *_postinc = postinc;
672 return 1;
673}
674
675
676
677
678static int misalignment_reg(unsigned long *registers, unsigned params,
679 unsigned opcode, unsigned long disp,
680 unsigned long **_register)
681{
682 params &= 0x7fffffff;
683
684 if (params & 0xffffff00)
685 return 0;
686
687 switch (params & 0xff) {
688 case DM0:
689 *_register = ®isters[Dreg_index[opcode & 0x03]];
690 break;
691 case DM1:
692 *_register = ®isters[Dreg_index[opcode >> 2 & 0x03]];
693 break;
694 case DM2:
695 *_register = ®isters[Dreg_index[opcode >> 4 & 0x03]];
696 break;
697 case AM0:
698 *_register = ®isters[Areg_index[opcode & 0x03]];
699 break;
700 case AM1:
701 *_register = ®isters[Areg_index[opcode >> 2 & 0x03]];
702 break;
703 case AM2:
704 *_register = ®isters[Areg_index[opcode >> 4 & 0x03]];
705 break;
706 case RM0:
707 *_register = ®isters[Rreg_index[opcode & 0x0f]];
708 break;
709 case RM1:
710 *_register = ®isters[Rreg_index[opcode >> 2 & 0x0f]];
711 break;
712 case RM2:
713 *_register = ®isters[Rreg_index[opcode >> 4 & 0x0f]];
714 break;
715 case RM4:
716 *_register = ®isters[Rreg_index[opcode >> 8 & 0x0f]];
717 break;
718 case RM6:
719 *_register = ®isters[Rreg_index[opcode >> 12 & 0x0f]];
720 break;
721 case RD0:
722 *_register = ®isters[Rreg_index[disp & 0x0f]];
723 break;
724 case RD2:
725 *_register = ®isters[Rreg_index[disp >> 4 & 0x0f]];
726 break;
727 case SP:
728 *_register = ®isters[REG_SP >> 2];
729 break;
730
731 default:
732 BUG();
733 return 0;
734 }
735
736 return 1;
737}
738
739
740
741
742static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode)
743{
744 unsigned long epsw = regs->epsw;
745 unsigned long NxorV;
746
747 kdebug("MOV_Lcc %x [flags=%lx]", opcode, epsw & 0xf);
748
749
750 NxorV = ((epsw >> 3) ^ epsw >> 1) & 1;
751
752 switch (opcode & 0xf) {
753 case 0x0:
754 if (NxorV)
755 goto take_the_loop;
756 return;
757 case 0x1:
758 if (!((epsw & EPSW_FLAG_Z) | NxorV))
759 goto take_the_loop;
760 return;
761 case 0x2:
762 if (!NxorV)
763 goto take_the_loop;
764 return;
765 case 0x3:
766 if ((epsw & EPSW_FLAG_Z) | NxorV)
767 goto take_the_loop;
768 return;
769
770 case 0x4:
771 if (epsw & EPSW_FLAG_C)
772 goto take_the_loop;
773 return;
774 case 0x5:
775 if (!(epsw & (EPSW_FLAG_C | EPSW_FLAG_Z)))
776 goto take_the_loop;
777 return;
778 case 0x6:
779 if (!(epsw & EPSW_FLAG_C))
780 goto take_the_loop;
781 return;
782 case 0x7:
783 if (epsw & (EPSW_FLAG_C | EPSW_FLAG_Z))
784 goto take_the_loop;
785 return;
786
787 case 0x8:
788 if (epsw & EPSW_FLAG_Z)
789 goto take_the_loop;
790 return;
791 case 0x9:
792 if (!(epsw & EPSW_FLAG_Z))
793 goto take_the_loop;
794 return;
795 case 0xa:
796 goto take_the_loop;
797
798 default:
799 BUG();
800 }
801
802take_the_loop:
803
804 kdebug("loop LAR=%lx", regs->lar);
805 regs->pc = regs->lar - 4;
806}
807
808
809
810
811#ifdef CONFIG_TEST_MISALIGNMENT_HANDLER
812static u8 __initdata testbuf[512] __attribute__((aligned(16))) = {
813 [257] = 0x11,
814 [258] = 0x22,
815 [259] = 0x33,
816 [260] = 0x44,
817};
818
819#define ASSERTCMP(X, OP, Y) \
820do { \
821 if (unlikely(!((X) OP (Y)))) { \
822 printk(KERN_ERR "\n"); \
823 printk(KERN_ERR "MISALIGN: Assertion failed at line %u\n", \
824 __LINE__); \
825 printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n", \
826 (unsigned long)(X), (unsigned long)(Y)); \
827 BUG(); \
828 } \
829} while(0)
830
831static int __init test_misalignment(void)
832{
833 register void *r asm("e0");
834 register u32 y asm("e1");
835 void *p = testbuf, *q;
836 u32 tmp, tmp2, x;
837
838 printk(KERN_NOTICE "==>test_misalignment() [testbuf=%p]\n", p);
839 p++;
840
841 printk(KERN_NOTICE "___ MOV (Am),Dn ___\n");
842 q = p + 256;
843 asm volatile("mov (%0),%1" : "+a"(q), "=d"(x));
844 ASSERTCMP(q, ==, p + 256);
845 ASSERTCMP(x, ==, 0x44332211);
846
847 printk(KERN_NOTICE "___ MOV (256,Am),Dn ___\n");
848 q = p;
849 asm volatile("mov (256,%0),%1" : "+a"(q), "=d"(x));
850 ASSERTCMP(q, ==, p);
851 ASSERTCMP(x, ==, 0x44332211);
852
853 printk(KERN_NOTICE "___ MOV (Di,Am),Dn ___\n");
854 tmp = 256;
855 q = p;
856 asm volatile("mov (%2,%0),%1" : "+a"(q), "=d"(x), "+d"(tmp));
857 ASSERTCMP(q, ==, p);
858 ASSERTCMP(x, ==, 0x44332211);
859 ASSERTCMP(tmp, ==, 256);
860
861 printk(KERN_NOTICE "___ MOV (256,Rm),Rn ___\n");
862 r = p;
863 asm volatile("mov (256,%0),%1" : "+r"(r), "=r"(y));
864 ASSERTCMP(r, ==, p);
865 ASSERTCMP(y, ==, 0x44332211);
866
867 printk(KERN_NOTICE "___ MOV (Rm+),Rn ___\n");
868 r = p + 256;
869 asm volatile("mov (%0+),%1" : "+r"(r), "=r"(y));
870 ASSERTCMP(r, ==, p + 256 + 4);
871 ASSERTCMP(y, ==, 0x44332211);
872
873 printk(KERN_NOTICE "___ MOV (Rm+,8),Rn ___\n");
874 r = p + 256;
875 asm volatile("mov (%0+,8),%1" : "+r"(r), "=r"(y));
876 ASSERTCMP(r, ==, p + 256 + 8);
877 ASSERTCMP(y, ==, 0x44332211);
878
879 printk(KERN_NOTICE "___ MOV (7,SP),Rn ___\n");
880 asm volatile(
881 "add -16,sp \n"
882 "mov +0x11,%0 \n"
883 "movbu %0,(7,sp) \n"
884 "mov +0x22,%0 \n"
885 "movbu %0,(8,sp) \n"
886 "mov +0x33,%0 \n"
887 "movbu %0,(9,sp) \n"
888 "mov +0x44,%0 \n"
889 "movbu %0,(10,sp) \n"
890 "mov (7,sp),%1 \n"
891 "add +16,sp \n"
892 : "+a"(q), "=d"(x));
893 ASSERTCMP(x, ==, 0x44332211);
894
895 printk(KERN_NOTICE "___ MOV (259,SP),Rn ___\n");
896 asm volatile(
897 "add -264,sp \n"
898 "mov +0x11,%0 \n"
899 "movbu %0,(259,sp) \n"
900 "mov +0x22,%0 \n"
901 "movbu %0,(260,sp) \n"
902 "mov +0x33,%0 \n"
903 "movbu %0,(261,sp) \n"
904 "mov +0x55,%0 \n"
905 "movbu %0,(262,sp) \n"
906 "mov (259,sp),%1 \n"
907 "add +264,sp \n"
908 : "+d"(tmp), "=d"(x));
909 ASSERTCMP(x, ==, 0x55332211);
910
911 printk(KERN_NOTICE "___ MOV (260,SP),Rn ___\n");
912 asm volatile(
913 "add -264,sp \n"
914 "mov +0x11,%0 \n"
915 "movbu %0,(260,sp) \n"
916 "mov +0x22,%0 \n"
917 "movbu %0,(261,sp) \n"
918 "mov +0x33,%0 \n"
919 "movbu %0,(262,sp) \n"
920 "mov +0x55,%0 \n"
921 "movbu %0,(263,sp) \n"
922 "mov (260,sp),%1 \n"
923 "add +264,sp \n"
924 : "+d"(tmp), "=d"(x));
925 ASSERTCMP(x, ==, 0x55332211);
926
927
928 printk(KERN_NOTICE "___ MOV_LNE ___\n");
929 tmp = 1;
930 tmp2 = 2;
931 q = p + 256;
932 asm volatile(
933 "setlb \n"
934 "mov %2,%3 \n"
935 "mov %1,%2 \n"
936 "cmp +0,%1 \n"
937 "mov_lne (%0+,4),%1"
938 : "+r"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
939 :
940 : "cc");
941 ASSERTCMP(q, ==, p + 256 + 12);
942 ASSERTCMP(x, ==, 0x44332211);
943
944 printk(KERN_NOTICE "___ MOV in SETLB ___\n");
945 tmp = 1;
946 tmp2 = 2;
947 q = p + 256;
948 asm volatile(
949 "setlb \n"
950 "mov %1,%3 \n"
951 "mov (%0+),%1 \n"
952 "cmp +0,%1 \n"
953 "lne "
954 : "+a"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
955 :
956 : "cc");
957
958 ASSERTCMP(q, ==, p + 256 + 8);
959 ASSERTCMP(x, ==, 0x44332211);
960
961 printk(KERN_NOTICE "<==test_misalignment()\n");
962 return 0;
963}
964
965arch_initcall(test_misalignment);
966
967#endif
968