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