aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>2013-03-25 14:18:07 -0400
committerRalf Baechle <ralf@linux-mips.org>2013-05-09 11:55:19 -0400
commit34c2f668d0f6b2ca1c076d8170d6cd4f2235a9d4 (patch)
tree9acdf8f14f17afde3c1f7d4abee55b0c8d3ca0ac
parentfb6883e5809c08e43de23581759af4570ca91b0f (diff)
MIPS: microMIPS: Add unaligned access support.
Add logic needed to handle unaligned accesses in microMIPS mode. Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com> Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
-rw-r--r--arch/mips/kernel/process.c101
-rw-r--r--arch/mips/kernel/unaligned.c1212
2 files changed, 1112 insertions, 201 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 3be4405c2d14..ef533760d2c8 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -7,6 +7,7 @@
7 * Copyright (C) 2005, 2006 by Ralf Baechle (ralf@linux-mips.org) 7 * Copyright (C) 2005, 2006 by Ralf Baechle (ralf@linux-mips.org)
8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
9 * Copyright (C) 2004 Thiemo Seufer 9 * Copyright (C) 2004 Thiemo Seufer
10 * Copyright (C) 2013 Imagination Technologies Ltd.
10 */ 11 */
11#include <linux/errno.h> 12#include <linux/errno.h>
12#include <linux/sched.h> 13#include <linux/sched.h>
@@ -243,34 +244,115 @@ struct mips_frame_info {
243 244
244static inline int is_ra_save_ins(union mips_instruction *ip) 245static inline int is_ra_save_ins(union mips_instruction *ip)
245{ 246{
247#ifdef CONFIG_CPU_MICROMIPS
248 union mips_instruction mmi;
249
250 /*
251 * swsp ra,offset
252 * swm16 reglist,offset(sp)
253 * swm32 reglist,offset(sp)
254 * sw32 ra,offset(sp)
255 * jradiussp - NOT SUPPORTED
256 *
257 * microMIPS is way more fun...
258 */
259 if (mm_insn_16bit(ip->halfword[0])) {
260 mmi.word = (ip->halfword[0] << 16);
261 return ((mmi.mm16_r5_format.opcode == mm_swsp16_op &&
262 mmi.mm16_r5_format.rt == 31) ||
263 (mmi.mm16_m_format.opcode == mm_pool16c_op &&
264 mmi.mm16_m_format.func == mm_swm16_op));
265 }
266 else {
267 mmi.halfword[0] = ip->halfword[1];
268 mmi.halfword[1] = ip->halfword[0];
269 return ((mmi.mm_m_format.opcode == mm_pool32b_op &&
270 mmi.mm_m_format.rd > 9 &&
271 mmi.mm_m_format.base == 29 &&
272 mmi.mm_m_format.func == mm_swm32_func) ||
273 (mmi.i_format.opcode == mm_sw32_op &&
274 mmi.i_format.rs == 29 &&
275 mmi.i_format.rt == 31));
276 }
277#else
246 /* sw / sd $ra, offset($sp) */ 278 /* sw / sd $ra, offset($sp) */
247 return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && 279 return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
248 ip->i_format.rs == 29 && 280 ip->i_format.rs == 29 &&
249 ip->i_format.rt == 31; 281 ip->i_format.rt == 31;
282#endif
250} 283}
251 284
252static inline int is_jal_jalr_jr_ins(union mips_instruction *ip) 285static inline int is_jal_jalr_jr_ins(union mips_instruction *ip)
253{ 286{
287#ifdef CONFIG_CPU_MICROMIPS
288 /*
289 * jr16,jrc,jalr16,jalr16
290 * jal
291 * jalr/jr,jalr.hb/jr.hb,jalrs,jalrs.hb
292 * jraddiusp - NOT SUPPORTED
293 *
294 * microMIPS is kind of more fun...
295 */
296 union mips_instruction mmi;
297
298 mmi.word = (ip->halfword[0] << 16);
299
300 if ((mmi.mm16_r5_format.opcode == mm_pool16c_op &&
301 (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) ||
302 ip->j_format.opcode == mm_jal32_op)
303 return 1;
304 if (ip->r_format.opcode != mm_pool32a_op ||
305 ip->r_format.func != mm_pool32axf_op)
306 return 0;
307 return (((ip->u_format.uimmediate >> 6) & mm_jalr_op) == mm_jalr_op);
308#else
254 if (ip->j_format.opcode == jal_op) 309 if (ip->j_format.opcode == jal_op)
255 return 1; 310 return 1;
256 if (ip->r_format.opcode != spec_op) 311 if (ip->r_format.opcode != spec_op)
257 return 0; 312 return 0;
258 return ip->r_format.func == jalr_op || ip->r_format.func == jr_op; 313 return ip->r_format.func == jalr_op || ip->r_format.func == jr_op;
314#endif
259} 315}
260 316
261static inline int is_sp_move_ins(union mips_instruction *ip) 317static inline int is_sp_move_ins(union mips_instruction *ip)
262{ 318{
319#ifdef CONFIG_CPU_MICROMIPS
320 /*
321 * addiusp -imm
322 * addius5 sp,-imm
323 * addiu32 sp,sp,-imm
324 * jradiussp - NOT SUPPORTED
325 *
326 * microMIPS is not more fun...
327 */
328 if (mm_insn_16bit(ip->halfword[0])) {
329 union mips_instruction mmi;
330
331 mmi.word = (ip->halfword[0] << 16);
332 return ((mmi.mm16_r3_format.opcode == mm_pool16d_op &&
333 mmi.mm16_r3_format.simmediate && mm_addiusp_func) ||
334 (mmi.mm16_r5_format.opcode == mm_pool16d_op &&
335 mmi.mm16_r5_format.rt == 29));
336 }
337 return (ip->mm_i_format.opcode == mm_addiu32_op &&
338 ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29);
339#else
263 /* addiu/daddiu sp,sp,-imm */ 340 /* addiu/daddiu sp,sp,-imm */
264 if (ip->i_format.rs != 29 || ip->i_format.rt != 29) 341 if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
265 return 0; 342 return 0;
266 if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) 343 if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
267 return 1; 344 return 1;
345#endif
268 return 0; 346 return 0;
269} 347}
270 348
271static int get_frame_info(struct mips_frame_info *info) 349static int get_frame_info(struct mips_frame_info *info)
272{ 350{
351#ifdef CONFIG_CPU_MICROMIPS
352 union mips_instruction *ip = (void *) (((char *) info->func) - 1);
353#else
273 union mips_instruction *ip = info->func; 354 union mips_instruction *ip = info->func;
355#endif
274 unsigned max_insns = info->func_size / sizeof(union mips_instruction); 356 unsigned max_insns = info->func_size / sizeof(union mips_instruction);
275 unsigned i; 357 unsigned i;
276 358
@@ -290,7 +372,26 @@ static int get_frame_info(struct mips_frame_info *info)
290 break; 372 break;
291 if (!info->frame_size) { 373 if (!info->frame_size) {
292 if (is_sp_move_ins(ip)) 374 if (is_sp_move_ins(ip))
375 {
376#ifdef CONFIG_CPU_MICROMIPS
377 if (mm_insn_16bit(ip->halfword[0]))
378 {
379 unsigned short tmp;
380
381 if (ip->halfword[0] & mm_addiusp_func)
382 {
383 tmp = (((ip->halfword[0] >> 1) & 0x1ff) << 2);
384 info->frame_size = -(signed short)(tmp | ((tmp & 0x100) ? 0xfe00 : 0));
385 } else {
386 tmp = (ip->halfword[0] >> 1);
387 info->frame_size = -(signed short)(tmp & 0xf);
388 }
389 ip = (void *) &ip->halfword[1];
390 ip--;
391 } else
392#endif
293 info->frame_size = - ip->i_format.simmediate; 393 info->frame_size = - ip->i_format.simmediate;
394 }
294 continue; 395 continue;
295 } 396 }
296 if (info->pc_offset == -1 && is_ra_save_ins(ip)) { 397 if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index f4c94ff3e3d3..0213906e3f82 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -87,6 +87,8 @@
87#include <asm/fpu_emulator.h> 87#include <asm/fpu_emulator.h>
88#include <asm/inst.h> 88#include <asm/inst.h>
89#include <asm/uaccess.h> 89#include <asm/uaccess.h>
90#include <asm/fpu.h>
91#include <asm/fpu_emulator.h>
90 92
91#define STR(x) __STR(x) 93#define STR(x) __STR(x)
92#define __STR(x) #x 94#define __STR(x) #x
@@ -104,14 +106,333 @@ static u32 unaligned_action;
104#endif 106#endif
105extern void show_registers(struct pt_regs *regs); 107extern void show_registers(struct pt_regs *regs);
106 108
109#ifdef __BIG_ENDIAN
110#define LoadHW(addr, value, res) \
111 __asm__ __volatile__ (".set\tnoat\n" \
112 "1:\tlb\t%0, 0(%2)\n" \
113 "2:\tlbu\t$1, 1(%2)\n\t" \
114 "sll\t%0, 0x8\n\t" \
115 "or\t%0, $1\n\t" \
116 "li\t%1, 0\n" \
117 "3:\t.set\tat\n\t" \
118 ".insn\n\t" \
119 ".section\t.fixup,\"ax\"\n\t" \
120 "4:\tli\t%1, %3\n\t" \
121 "j\t3b\n\t" \
122 ".previous\n\t" \
123 ".section\t__ex_table,\"a\"\n\t" \
124 STR(PTR)"\t1b, 4b\n\t" \
125 STR(PTR)"\t2b, 4b\n\t" \
126 ".previous" \
127 : "=&r" (value), "=r" (res) \
128 : "r" (addr), "i" (-EFAULT));
129
130#define LoadW(addr, value, res) \
131 __asm__ __volatile__ ( \
132 "1:\tlwl\t%0, (%2)\n" \
133 "2:\tlwr\t%0, 3(%2)\n\t" \
134 "li\t%1, 0\n" \
135 "3:\n\t" \
136 ".insn\n\t" \
137 ".section\t.fixup,\"ax\"\n\t" \
138 "4:\tli\t%1, %3\n\t" \
139 "j\t3b\n\t" \
140 ".previous\n\t" \
141 ".section\t__ex_table,\"a\"\n\t" \
142 STR(PTR)"\t1b, 4b\n\t" \
143 STR(PTR)"\t2b, 4b\n\t" \
144 ".previous" \
145 : "=&r" (value), "=r" (res) \
146 : "r" (addr), "i" (-EFAULT));
147
148#define LoadHWU(addr, value, res) \
149 __asm__ __volatile__ ( \
150 ".set\tnoat\n" \
151 "1:\tlbu\t%0, 0(%2)\n" \
152 "2:\tlbu\t$1, 1(%2)\n\t" \
153 "sll\t%0, 0x8\n\t" \
154 "or\t%0, $1\n\t" \
155 "li\t%1, 0\n" \
156 "3:\n\t" \
157 ".insn\n\t" \
158 ".set\tat\n\t" \
159 ".section\t.fixup,\"ax\"\n\t" \
160 "4:\tli\t%1, %3\n\t" \
161 "j\t3b\n\t" \
162 ".previous\n\t" \
163 ".section\t__ex_table,\"a\"\n\t" \
164 STR(PTR)"\t1b, 4b\n\t" \
165 STR(PTR)"\t2b, 4b\n\t" \
166 ".previous" \
167 : "=&r" (value), "=r" (res) \
168 : "r" (addr), "i" (-EFAULT));
169
170#define LoadWU(addr, value, res) \
171 __asm__ __volatile__ ( \
172 "1:\tlwl\t%0, (%2)\n" \
173 "2:\tlwr\t%0, 3(%2)\n\t" \
174 "dsll\t%0, %0, 32\n\t" \
175 "dsrl\t%0, %0, 32\n\t" \
176 "li\t%1, 0\n" \
177 "3:\n\t" \
178 ".insn\n\t" \
179 "\t.section\t.fixup,\"ax\"\n\t" \
180 "4:\tli\t%1, %3\n\t" \
181 "j\t3b\n\t" \
182 ".previous\n\t" \
183 ".section\t__ex_table,\"a\"\n\t" \
184 STR(PTR)"\t1b, 4b\n\t" \
185 STR(PTR)"\t2b, 4b\n\t" \
186 ".previous" \
187 : "=&r" (value), "=r" (res) \
188 : "r" (addr), "i" (-EFAULT));
189
190#define LoadDW(addr, value, res) \
191 __asm__ __volatile__ ( \
192 "1:\tldl\t%0, (%2)\n" \
193 "2:\tldr\t%0, 7(%2)\n\t" \
194 "li\t%1, 0\n" \
195 "3:\n\t" \
196 ".insn\n\t" \
197 "\t.section\t.fixup,\"ax\"\n\t" \
198 "4:\tli\t%1, %3\n\t" \
199 "j\t3b\n\t" \
200 ".previous\n\t" \
201 ".section\t__ex_table,\"a\"\n\t" \
202 STR(PTR)"\t1b, 4b\n\t" \
203 STR(PTR)"\t2b, 4b\n\t" \
204 ".previous" \
205 : "=&r" (value), "=r" (res) \
206 : "r" (addr), "i" (-EFAULT));
207
208#define StoreHW(addr, value, res) \
209 __asm__ __volatile__ ( \
210 ".set\tnoat\n" \
211 "1:\tsb\t%1, 1(%2)\n\t" \
212 "srl\t$1, %1, 0x8\n" \
213 "2:\tsb\t$1, 0(%2)\n\t" \
214 ".set\tat\n\t" \
215 "li\t%0, 0\n" \
216 "3:\n\t" \
217 ".insn\n\t" \
218 ".section\t.fixup,\"ax\"\n\t" \
219 "4:\tli\t%0, %3\n\t" \
220 "j\t3b\n\t" \
221 ".previous\n\t" \
222 ".section\t__ex_table,\"a\"\n\t" \
223 STR(PTR)"\t1b, 4b\n\t" \
224 STR(PTR)"\t2b, 4b\n\t" \
225 ".previous" \
226 : "=r" (res) \
227 : "r" (value), "r" (addr), "i" (-EFAULT));
228
229#define StoreW(addr, value, res) \
230 __asm__ __volatile__ ( \
231 "1:\tswl\t%1,(%2)\n" \
232 "2:\tswr\t%1, 3(%2)\n\t" \
233 "li\t%0, 0\n" \
234 "3:\n\t" \
235 ".insn\n\t" \
236 ".section\t.fixup,\"ax\"\n\t" \
237 "4:\tli\t%0, %3\n\t" \
238 "j\t3b\n\t" \
239 ".previous\n\t" \
240 ".section\t__ex_table,\"a\"\n\t" \
241 STR(PTR)"\t1b, 4b\n\t" \
242 STR(PTR)"\t2b, 4b\n\t" \
243 ".previous" \
244 : "=r" (res) \
245 : "r" (value), "r" (addr), "i" (-EFAULT));
246
247#define StoreDW(addr, value, res) \
248 __asm__ __volatile__ ( \
249 "1:\tsdl\t%1,(%2)\n" \
250 "2:\tsdr\t%1, 7(%2)\n\t" \
251 "li\t%0, 0\n" \
252 "3:\n\t" \
253 ".insn\n\t" \
254 ".section\t.fixup,\"ax\"\n\t" \
255 "4:\tli\t%0, %3\n\t" \
256 "j\t3b\n\t" \
257 ".previous\n\t" \
258 ".section\t__ex_table,\"a\"\n\t" \
259 STR(PTR)"\t1b, 4b\n\t" \
260 STR(PTR)"\t2b, 4b\n\t" \
261 ".previous" \
262 : "=r" (res) \
263 : "r" (value), "r" (addr), "i" (-EFAULT));
264#endif
265
266#ifdef __LITTLE_ENDIAN
267#define LoadHW(addr, value, res) \
268 __asm__ __volatile__ (".set\tnoat\n" \
269 "1:\tlb\t%0, 1(%2)\n" \
270 "2:\tlbu\t$1, 0(%2)\n\t" \
271 "sll\t%0, 0x8\n\t" \
272 "or\t%0, $1\n\t" \
273 "li\t%1, 0\n" \
274 "3:\t.set\tat\n\t" \
275 ".insn\n\t" \
276 ".section\t.fixup,\"ax\"\n\t" \
277 "4:\tli\t%1, %3\n\t" \
278 "j\t3b\n\t" \
279 ".previous\n\t" \
280 ".section\t__ex_table,\"a\"\n\t" \
281 STR(PTR)"\t1b, 4b\n\t" \
282 STR(PTR)"\t2b, 4b\n\t" \
283 ".previous" \
284 : "=&r" (value), "=r" (res) \
285 : "r" (addr), "i" (-EFAULT));
286
287#define LoadW(addr, value, res) \
288 __asm__ __volatile__ ( \
289 "1:\tlwl\t%0, 3(%2)\n" \
290 "2:\tlwr\t%0, (%2)\n\t" \
291 "li\t%1, 0\n" \
292 "3:\n\t" \
293 ".insn\n\t" \
294 ".section\t.fixup,\"ax\"\n\t" \
295 "4:\tli\t%1, %3\n\t" \
296 "j\t3b\n\t" \
297 ".previous\n\t" \
298 ".section\t__ex_table,\"a\"\n\t" \
299 STR(PTR)"\t1b, 4b\n\t" \
300 STR(PTR)"\t2b, 4b\n\t" \
301 ".previous" \
302 : "=&r" (value), "=r" (res) \
303 : "r" (addr), "i" (-EFAULT));
304
305#define LoadHWU(addr, value, res) \
306 __asm__ __volatile__ ( \
307 ".set\tnoat\n" \
308 "1:\tlbu\t%0, 1(%2)\n" \
309 "2:\tlbu\t$1, 0(%2)\n\t" \
310 "sll\t%0, 0x8\n\t" \
311 "or\t%0, $1\n\t" \
312 "li\t%1, 0\n" \
313 "3:\n\t" \
314 ".insn\n\t" \
315 ".set\tat\n\t" \
316 ".section\t.fixup,\"ax\"\n\t" \
317 "4:\tli\t%1, %3\n\t" \
318 "j\t3b\n\t" \
319 ".previous\n\t" \
320 ".section\t__ex_table,\"a\"\n\t" \
321 STR(PTR)"\t1b, 4b\n\t" \
322 STR(PTR)"\t2b, 4b\n\t" \
323 ".previous" \
324 : "=&r" (value), "=r" (res) \
325 : "r" (addr), "i" (-EFAULT));
326
327#define LoadWU(addr, value, res) \
328 __asm__ __volatile__ ( \
329 "1:\tlwl\t%0, 3(%2)\n" \
330 "2:\tlwr\t%0, (%2)\n\t" \
331 "dsll\t%0, %0, 32\n\t" \
332 "dsrl\t%0, %0, 32\n\t" \
333 "li\t%1, 0\n" \
334 "3:\n\t" \
335 ".insn\n\t" \
336 "\t.section\t.fixup,\"ax\"\n\t" \
337 "4:\tli\t%1, %3\n\t" \
338 "j\t3b\n\t" \
339 ".previous\n\t" \
340 ".section\t__ex_table,\"a\"\n\t" \
341 STR(PTR)"\t1b, 4b\n\t" \
342 STR(PTR)"\t2b, 4b\n\t" \
343 ".previous" \
344 : "=&r" (value), "=r" (res) \
345 : "r" (addr), "i" (-EFAULT));
346
347#define LoadDW(addr, value, res) \
348 __asm__ __volatile__ ( \
349 "1:\tldl\t%0, 7(%2)\n" \
350 "2:\tldr\t%0, (%2)\n\t" \
351 "li\t%1, 0\n" \
352 "3:\n\t" \
353 ".insn\n\t" \
354 "\t.section\t.fixup,\"ax\"\n\t" \
355 "4:\tli\t%1, %3\n\t" \
356 "j\t3b\n\t" \
357 ".previous\n\t" \
358 ".section\t__ex_table,\"a\"\n\t" \
359 STR(PTR)"\t1b, 4b\n\t" \
360 STR(PTR)"\t2b, 4b\n\t" \
361 ".previous" \
362 : "=&r" (value), "=r" (res) \
363 : "r" (addr), "i" (-EFAULT));
364
365#define StoreHW(addr, value, res) \
366 __asm__ __volatile__ ( \
367 ".set\tnoat\n" \
368 "1:\tsb\t%1, 0(%2)\n\t" \
369 "srl\t$1,%1, 0x8\n" \
370 "2:\tsb\t$1, 1(%2)\n\t" \
371 ".set\tat\n\t" \
372 "li\t%0, 0\n" \
373 "3:\n\t" \
374 ".insn\n\t" \
375 ".section\t.fixup,\"ax\"\n\t" \
376 "4:\tli\t%0, %3\n\t" \
377 "j\t3b\n\t" \
378 ".previous\n\t" \
379 ".section\t__ex_table,\"a\"\n\t" \
380 STR(PTR)"\t1b, 4b\n\t" \
381 STR(PTR)"\t2b, 4b\n\t" \
382 ".previous" \
383 : "=r" (res) \
384 : "r" (value), "r" (addr), "i" (-EFAULT));
385
386#define StoreW(addr, value, res) \
387 __asm__ __volatile__ ( \
388 "1:\tswl\t%1, 3(%2)\n" \
389 "2:\tswr\t%1, (%2)\n\t" \
390 "li\t%0, 0\n" \
391 "3:\n\t" \
392 ".insn\n\t" \
393 ".section\t.fixup,\"ax\"\n\t" \
394 "4:\tli\t%0, %3\n\t" \
395 "j\t3b\n\t" \
396 ".previous\n\t" \
397 ".section\t__ex_table,\"a\"\n\t" \
398 STR(PTR)"\t1b, 4b\n\t" \
399 STR(PTR)"\t2b, 4b\n\t" \
400 ".previous" \
401 : "=r" (res) \
402 : "r" (value), "r" (addr), "i" (-EFAULT));
403
404#define StoreDW(addr, value, res) \
405 __asm__ __volatile__ ( \
406 "1:\tsdl\t%1, 7(%2)\n" \
407 "2:\tsdr\t%1, (%2)\n\t" \
408 "li\t%0, 0\n" \
409 "3:\n\t" \
410 ".insn\n\t" \
411 ".section\t.fixup,\"ax\"\n\t" \
412 "4:\tli\t%0, %3\n\t" \
413 "j\t3b\n\t" \
414 ".previous\n\t" \
415 ".section\t__ex_table,\"a\"\n\t" \
416 STR(PTR)"\t1b, 4b\n\t" \
417 STR(PTR)"\t2b, 4b\n\t" \
418 ".previous" \
419 : "=r" (res) \
420 : "r" (value), "r" (addr), "i" (-EFAULT));
421#endif
422
107static void emulate_load_store_insn(struct pt_regs *regs, 423static void emulate_load_store_insn(struct pt_regs *regs,
108 void __user *addr, unsigned int __user *pc) 424 void __user *addr, unsigned int __user *pc)
109{ 425{
110 union mips_instruction insn; 426 union mips_instruction insn;
111 unsigned long value; 427 unsigned long value;
112 unsigned int res; 428 unsigned int res;
429 unsigned long origpc;
430 unsigned long orig31;
113 void __user *fault_addr = NULL; 431 void __user *fault_addr = NULL;
114 432
433 origpc = (unsigned long)pc;
434 orig31 = regs->regs[31];
435
115 perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); 436 perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
116 437
117 /* 438 /*
@@ -120,22 +441,22 @@ static void emulate_load_store_insn(struct pt_regs *regs,
120 __get_user(insn.word, pc); 441 __get_user(insn.word, pc);
121 442
122 switch (insn.i_format.opcode) { 443 switch (insn.i_format.opcode) {
123 /* 444 /*
124 * These are instructions that a compiler doesn't generate. We 445 * These are instructions that a compiler doesn't generate. We
125 * can assume therefore that the code is MIPS-aware and 446 * can assume therefore that the code is MIPS-aware and
126 * really buggy. Emulating these instructions would break the 447 * really buggy. Emulating these instructions would break the
127 * semantics anyway. 448 * semantics anyway.
128 */ 449 */
129 case ll_op: 450 case ll_op:
130 case lld_op: 451 case lld_op:
131 case sc_op: 452 case sc_op:
132 case scd_op: 453 case scd_op:
133 454
134 /* 455 /*
135 * For these instructions the only way to create an address 456 * For these instructions the only way to create an address
136 * error is an attempted access to kernel/supervisor address 457 * error is an attempted access to kernel/supervisor address
137 * space. 458 * space.
138 */ 459 */
139 case ldl_op: 460 case ldl_op:
140 case ldr_op: 461 case ldr_op:
141 case lwl_op: 462 case lwl_op:
@@ -149,36 +470,15 @@ static void emulate_load_store_insn(struct pt_regs *regs,
149 case sb_op: 470 case sb_op:
150 goto sigbus; 471 goto sigbus;
151 472
152 /* 473 /*
153 * The remaining opcodes are the ones that are really of interest. 474 * The remaining opcodes are the ones that are really of
154 */ 475 * interest.
476 */
155 case lh_op: 477 case lh_op:
156 if (!access_ok(VERIFY_READ, addr, 2)) 478 if (!access_ok(VERIFY_READ, addr, 2))
157 goto sigbus; 479 goto sigbus;
158 480
159 __asm__ __volatile__ (".set\tnoat\n" 481 LoadHW(addr, value, res);
160#ifdef __BIG_ENDIAN
161 "1:\tlb\t%0, 0(%2)\n"
162 "2:\tlbu\t$1, 1(%2)\n\t"
163#endif
164#ifdef __LITTLE_ENDIAN
165 "1:\tlb\t%0, 1(%2)\n"
166 "2:\tlbu\t$1, 0(%2)\n\t"
167#endif
168 "sll\t%0, 0x8\n\t"
169 "or\t%0, $1\n\t"
170 "li\t%1, 0\n"
171 "3:\t.set\tat\n\t"
172 ".section\t.fixup,\"ax\"\n\t"
173 "4:\tli\t%1, %3\n\t"
174 "j\t3b\n\t"
175 ".previous\n\t"
176 ".section\t__ex_table,\"a\"\n\t"
177 STR(PTR)"\t1b, 4b\n\t"
178 STR(PTR)"\t2b, 4b\n\t"
179 ".previous"
180 : "=&r" (value), "=r" (res)
181 : "r" (addr), "i" (-EFAULT));
182 if (res) 482 if (res)
183 goto fault; 483 goto fault;
184 compute_return_epc(regs); 484 compute_return_epc(regs);
@@ -189,26 +489,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
189 if (!access_ok(VERIFY_READ, addr, 4)) 489 if (!access_ok(VERIFY_READ, addr, 4))
190 goto sigbus; 490 goto sigbus;
191 491
192 __asm__ __volatile__ ( 492 LoadW(addr, value, res);
193#ifdef __BIG_ENDIAN
194 "1:\tlwl\t%0, (%2)\n"
195 "2:\tlwr\t%0, 3(%2)\n\t"
196#endif
197#ifdef __LITTLE_ENDIAN
198 "1:\tlwl\t%0, 3(%2)\n"
199 "2:\tlwr\t%0, (%2)\n\t"
200#endif
201 "li\t%1, 0\n"
202 "3:\t.section\t.fixup,\"ax\"\n\t"
203 "4:\tli\t%1, %3\n\t"
204 "j\t3b\n\t"
205 ".previous\n\t"
206 ".section\t__ex_table,\"a\"\n\t"
207 STR(PTR)"\t1b, 4b\n\t"
208 STR(PTR)"\t2b, 4b\n\t"
209 ".previous"
210 : "=&r" (value), "=r" (res)
211 : "r" (addr), "i" (-EFAULT));
212 if (res) 493 if (res)
213 goto fault; 494 goto fault;
214 compute_return_epc(regs); 495 compute_return_epc(regs);
@@ -219,30 +500,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
219 if (!access_ok(VERIFY_READ, addr, 2)) 500 if (!access_ok(VERIFY_READ, addr, 2))
220 goto sigbus; 501 goto sigbus;
221 502
222 __asm__ __volatile__ ( 503 LoadHWU(addr, value, res);
223 ".set\tnoat\n"
224#ifdef __BIG_ENDIAN
225 "1:\tlbu\t%0, 0(%2)\n"
226 "2:\tlbu\t$1, 1(%2)\n\t"
227#endif
228#ifdef __LITTLE_ENDIAN
229 "1:\tlbu\t%0, 1(%2)\n"
230 "2:\tlbu\t$1, 0(%2)\n\t"
231#endif
232 "sll\t%0, 0x8\n\t"
233 "or\t%0, $1\n\t"
234 "li\t%1, 0\n"
235 "3:\t.set\tat\n\t"
236 ".section\t.fixup,\"ax\"\n\t"
237 "4:\tli\t%1, %3\n\t"
238 "j\t3b\n\t"
239 ".previous\n\t"
240 ".section\t__ex_table,\"a\"\n\t"
241 STR(PTR)"\t1b, 4b\n\t"
242 STR(PTR)"\t2b, 4b\n\t"
243 ".previous"
244 : "=&r" (value), "=r" (res)
245 : "r" (addr), "i" (-EFAULT));
246 if (res) 504 if (res)
247 goto fault; 505 goto fault;
248 compute_return_epc(regs); 506 compute_return_epc(regs);
@@ -261,28 +519,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
261 if (!access_ok(VERIFY_READ, addr, 4)) 519 if (!access_ok(VERIFY_READ, addr, 4))
262 goto sigbus; 520 goto sigbus;
263 521
264 __asm__ __volatile__ ( 522 LoadWU(addr, value, res);
265#ifdef __BIG_ENDIAN
266 "1:\tlwl\t%0, (%2)\n"
267 "2:\tlwr\t%0, 3(%2)\n\t"
268#endif
269#ifdef __LITTLE_ENDIAN
270 "1:\tlwl\t%0, 3(%2)\n"
271 "2:\tlwr\t%0, (%2)\n\t"
272#endif
273 "dsll\t%0, %0, 32\n\t"
274 "dsrl\t%0, %0, 32\n\t"
275 "li\t%1, 0\n"
276 "3:\t.section\t.fixup,\"ax\"\n\t"
277 "4:\tli\t%1, %3\n\t"
278 "j\t3b\n\t"
279 ".previous\n\t"
280 ".section\t__ex_table,\"a\"\n\t"
281 STR(PTR)"\t1b, 4b\n\t"
282 STR(PTR)"\t2b, 4b\n\t"
283 ".previous"
284 : "=&r" (value), "=r" (res)
285 : "r" (addr), "i" (-EFAULT));
286 if (res) 523 if (res)
287 goto fault; 524 goto fault;
288 compute_return_epc(regs); 525 compute_return_epc(regs);
@@ -305,26 +542,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
305 if (!access_ok(VERIFY_READ, addr, 8)) 542 if (!access_ok(VERIFY_READ, addr, 8))
306 goto sigbus; 543 goto sigbus;
307 544
308 __asm__ __volatile__ ( 545 LoadDW(addr, value, res);
309#ifdef __BIG_ENDIAN
310 "1:\tldl\t%0, (%2)\n"
311 "2:\tldr\t%0, 7(%2)\n\t"
312#endif
313#ifdef __LITTLE_ENDIAN
314 "1:\tldl\t%0, 7(%2)\n"
315 "2:\tldr\t%0, (%2)\n\t"
316#endif
317 "li\t%1, 0\n"
318 "3:\t.section\t.fixup,\"ax\"\n\t"
319 "4:\tli\t%1, %3\n\t"
320 "j\t3b\n\t"
321 ".previous\n\t"
322 ".section\t__ex_table,\"a\"\n\t"
323 STR(PTR)"\t1b, 4b\n\t"
324 STR(PTR)"\t2b, 4b\n\t"
325 ".previous"
326 : "=&r" (value), "=r" (res)
327 : "r" (addr), "i" (-EFAULT));
328 if (res) 546 if (res)
329 goto fault; 547 goto fault;
330 compute_return_epc(regs); 548 compute_return_epc(regs);
@@ -339,68 +557,22 @@ static void emulate_load_store_insn(struct pt_regs *regs,
339 if (!access_ok(VERIFY_WRITE, addr, 2)) 557 if (!access_ok(VERIFY_WRITE, addr, 2))
340 goto sigbus; 558 goto sigbus;
341 559
560 compute_return_epc(regs);
342 value = regs->regs[insn.i_format.rt]; 561 value = regs->regs[insn.i_format.rt];
343 __asm__ __volatile__ ( 562 StoreHW(addr, value, res);
344#ifdef __BIG_ENDIAN
345 ".set\tnoat\n"
346 "1:\tsb\t%1, 1(%2)\n\t"
347 "srl\t$1, %1, 0x8\n"
348 "2:\tsb\t$1, 0(%2)\n\t"
349 ".set\tat\n\t"
350#endif
351#ifdef __LITTLE_ENDIAN
352 ".set\tnoat\n"
353 "1:\tsb\t%1, 0(%2)\n\t"
354 "srl\t$1,%1, 0x8\n"
355 "2:\tsb\t$1, 1(%2)\n\t"
356 ".set\tat\n\t"
357#endif
358 "li\t%0, 0\n"
359 "3:\n\t"
360 ".section\t.fixup,\"ax\"\n\t"
361 "4:\tli\t%0, %3\n\t"
362 "j\t3b\n\t"
363 ".previous\n\t"
364 ".section\t__ex_table,\"a\"\n\t"
365 STR(PTR)"\t1b, 4b\n\t"
366 STR(PTR)"\t2b, 4b\n\t"
367 ".previous"
368 : "=r" (res)
369 : "r" (value), "r" (addr), "i" (-EFAULT));
370 if (res) 563 if (res)
371 goto fault; 564 goto fault;
372 compute_return_epc(regs);
373 break; 565 break;
374 566
375 case sw_op: 567 case sw_op:
376 if (!access_ok(VERIFY_WRITE, addr, 4)) 568 if (!access_ok(VERIFY_WRITE, addr, 4))
377 goto sigbus; 569 goto sigbus;
378 570
571 compute_return_epc(regs);
379 value = regs->regs[insn.i_format.rt]; 572 value = regs->regs[insn.i_format.rt];
380 __asm__ __volatile__ ( 573 StoreW(addr, value, res);
381#ifdef __BIG_ENDIAN
382 "1:\tswl\t%1,(%2)\n"
383 "2:\tswr\t%1, 3(%2)\n\t"
384#endif
385#ifdef __LITTLE_ENDIAN
386 "1:\tswl\t%1, 3(%2)\n"
387 "2:\tswr\t%1, (%2)\n\t"
388#endif
389 "li\t%0, 0\n"
390 "3:\n\t"
391 ".section\t.fixup,\"ax\"\n\t"
392 "4:\tli\t%0, %3\n\t"
393 "j\t3b\n\t"
394 ".previous\n\t"
395 ".section\t__ex_table,\"a\"\n\t"
396 STR(PTR)"\t1b, 4b\n\t"
397 STR(PTR)"\t2b, 4b\n\t"
398 ".previous"
399 : "=r" (res)
400 : "r" (value), "r" (addr), "i" (-EFAULT));
401 if (res) 574 if (res)
402 goto fault; 575 goto fault;
403 compute_return_epc(regs);
404 break; 576 break;
405 577
406 case sd_op: 578 case sd_op:
@@ -415,31 +587,11 @@ static void emulate_load_store_insn(struct pt_regs *regs,
415 if (!access_ok(VERIFY_WRITE, addr, 8)) 587 if (!access_ok(VERIFY_WRITE, addr, 8))
416 goto sigbus; 588 goto sigbus;
417 589
590 compute_return_epc(regs);
418 value = regs->regs[insn.i_format.rt]; 591 value = regs->regs[insn.i_format.rt];
419 __asm__ __volatile__ ( 592 StoreDW(addr, value, res);
420#ifdef __BIG_ENDIAN
421 "1:\tsdl\t%1,(%2)\n"
422 "2:\tsdr\t%1, 7(%2)\n\t"
423#endif
424#ifdef __LITTLE_ENDIAN
425 "1:\tsdl\t%1, 7(%2)\n"
426 "2:\tsdr\t%1, (%2)\n\t"
427#endif
428 "li\t%0, 0\n"
429 "3:\n\t"
430 ".section\t.fixup,\"ax\"\n\t"
431 "4:\tli\t%0, %3\n\t"
432 "j\t3b\n\t"
433 ".previous\n\t"
434 ".section\t__ex_table,\"a\"\n\t"
435 STR(PTR)"\t1b, 4b\n\t"
436 STR(PTR)"\t2b, 4b\n\t"
437 ".previous"
438 : "=r" (res)
439 : "r" (value), "r" (addr), "i" (-EFAULT));
440 if (res) 593 if (res)
441 goto fault; 594 goto fault;
442 compute_return_epc(regs);
443 break; 595 break;
444#endif /* CONFIG_64BIT */ 596#endif /* CONFIG_64BIT */
445 597
@@ -502,6 +654,635 @@ static void emulate_load_store_insn(struct pt_regs *regs,
502 return; 654 return;
503 655
504fault: 656fault:
657 /* roll back jump/branch */
658 regs->cp0_epc = origpc;
659 regs->regs[31] = orig31;
660 /* Did we have an exception handler installed? */
661 if (fixup_exception(regs))
662 return;
663
664 die_if_kernel("Unhandled kernel unaligned access", regs);
665 force_sig(SIGSEGV, current);
666
667 return;
668
669sigbus:
670 die_if_kernel("Unhandled kernel unaligned access", regs);
671 force_sig(SIGBUS, current);
672
673 return;
674
675sigill:
676 die_if_kernel
677 ("Unhandled kernel unaligned access or invalid instruction", regs);
678 force_sig(SIGILL, current);
679}
680
681/* Recode table from 16-bit register notation to 32-bit GPR. */
682const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
683
684/* Recode table from 16-bit STORE register notation to 32-bit GPR. */
685const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
686
687void emulate_load_store_microMIPS(struct pt_regs *regs, void __user * addr)
688{
689 unsigned long value;
690 unsigned int res;
691 int i;
692 unsigned int reg = 0, rvar;
693 unsigned long orig31;
694 u16 __user *pc16;
695 u16 halfword;
696 unsigned int word;
697 unsigned long origpc, contpc;
698 union mips_instruction insn;
699 struct mm_decoded_insn mminsn;
700 void __user *fault_addr = NULL;
701
702 origpc = regs->cp0_epc;
703 orig31 = regs->regs[31];
704
705 mminsn.micro_mips_mode = 1;
706
707 /*
708 * This load never faults.
709 */
710 pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
711 __get_user(halfword, pc16);
712 pc16++;
713 contpc = regs->cp0_epc + 2;
714 word = ((unsigned int)halfword << 16);
715 mminsn.pc_inc = 2;
716
717 if (!mm_insn_16bit(halfword)) {
718 __get_user(halfword, pc16);
719 pc16++;
720 contpc = regs->cp0_epc + 4;
721 mminsn.pc_inc = 4;
722 word |= halfword;
723 }
724 mminsn.insn = word;
725
726 if (get_user(halfword, pc16))
727 goto fault;
728 mminsn.next_pc_inc = 2;
729 word = ((unsigned int)halfword << 16);
730
731 if (!mm_insn_16bit(halfword)) {
732 pc16++;
733 if (get_user(halfword, pc16))
734 goto fault;
735 mminsn.next_pc_inc = 4;
736 word |= halfword;
737 }
738 mminsn.next_insn = word;
739
740 insn = (union mips_instruction)(mminsn.insn);
741 if (mm_isBranchInstr(regs, mminsn, &contpc))
742 insn = (union mips_instruction)(mminsn.next_insn);
743
744 /* Parse instruction to find what to do */
745
746 switch (insn.mm_i_format.opcode) {
747
748 case mm_pool32a_op:
749 switch (insn.mm_x_format.func) {
750 case mm_lwxs_op:
751 reg = insn.mm_x_format.rd;
752 goto loadW;
753 }
754
755 goto sigbus;
756
757 case mm_pool32b_op:
758 switch (insn.mm_m_format.func) {
759 case mm_lwp_func:
760 reg = insn.mm_m_format.rd;
761 if (reg == 31)
762 goto sigbus;
763
764 if (!access_ok(VERIFY_READ, addr, 8))
765 goto sigbus;
766
767 LoadW(addr, value, res);
768 if (res)
769 goto fault;
770 regs->regs[reg] = value;
771 addr += 4;
772 LoadW(addr, value, res);
773 if (res)
774 goto fault;
775 regs->regs[reg + 1] = value;
776 goto success;
777
778 case mm_swp_func:
779 reg = insn.mm_m_format.rd;
780 if (reg == 31)
781 goto sigbus;
782
783 if (!access_ok(VERIFY_WRITE, addr, 8))
784 goto sigbus;
785
786 value = regs->regs[reg];
787 StoreW(addr, value, res);
788 if (res)
789 goto fault;
790 addr += 4;
791 value = regs->regs[reg + 1];
792 StoreW(addr, value, res);
793 if (res)
794 goto fault;
795 goto success;
796
797 case mm_ldp_func:
798#ifdef CONFIG_64BIT
799 reg = insn.mm_m_format.rd;
800 if (reg == 31)
801 goto sigbus;
802
803 if (!access_ok(VERIFY_READ, addr, 16))
804 goto sigbus;
805
806 LoadDW(addr, value, res);
807 if (res)
808 goto fault;
809 regs->regs[reg] = value;
810 addr += 8;
811 LoadDW(addr, value, res);
812 if (res)
813 goto fault;
814 regs->regs[reg + 1] = value;
815 goto success;
816#endif /* CONFIG_64BIT */
817
818 goto sigill;
819
820 case mm_sdp_func:
821#ifdef CONFIG_64BIT
822 reg = insn.mm_m_format.rd;
823 if (reg == 31)
824 goto sigbus;
825
826 if (!access_ok(VERIFY_WRITE, addr, 16))
827 goto sigbus;
828
829 value = regs->regs[reg];
830 StoreDW(addr, value, res);
831 if (res)
832 goto fault;
833 addr += 8;
834 value = regs->regs[reg + 1];
835 StoreDW(addr, value, res);
836 if (res)
837 goto fault;
838 goto success;
839#endif /* CONFIG_64BIT */
840
841 goto sigill;
842
843 case mm_lwm32_func:
844 reg = insn.mm_m_format.rd;
845 rvar = reg & 0xf;
846 if ((rvar > 9) || !reg)
847 goto sigill;
848 if (reg & 0x10) {
849 if (!access_ok
850 (VERIFY_READ, addr, 4 * (rvar + 1)))
851 goto sigbus;
852 } else {
853 if (!access_ok(VERIFY_READ, addr, 4 * rvar))
854 goto sigbus;
855 }
856 if (rvar == 9)
857 rvar = 8;
858 for (i = 16; rvar; rvar--, i++) {
859 LoadW(addr, value, res);
860 if (res)
861 goto fault;
862 addr += 4;
863 regs->regs[i] = value;
864 }
865 if ((reg & 0xf) == 9) {
866 LoadW(addr, value, res);
867 if (res)
868 goto fault;
869 addr += 4;
870 regs->regs[30] = value;
871 }
872 if (reg & 0x10) {
873 LoadW(addr, value, res);
874 if (res)
875 goto fault;
876 regs->regs[31] = value;
877 }
878 goto success;
879
880 case mm_swm32_func:
881 reg = insn.mm_m_format.rd;
882 rvar = reg & 0xf;
883 if ((rvar > 9) || !reg)
884 goto sigill;
885 if (reg & 0x10) {
886 if (!access_ok
887 (VERIFY_WRITE, addr, 4 * (rvar + 1)))
888 goto sigbus;
889 } else {
890 if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
891 goto sigbus;
892 }
893 if (rvar == 9)
894 rvar = 8;
895 for (i = 16; rvar; rvar--, i++) {
896 value = regs->regs[i];
897 StoreW(addr, value, res);
898 if (res)
899 goto fault;
900 addr += 4;
901 }
902 if ((reg & 0xf) == 9) {
903 value = regs->regs[30];
904 StoreW(addr, value, res);
905 if (res)
906 goto fault;
907 addr += 4;
908 }
909 if (reg & 0x10) {
910 value = regs->regs[31];
911 StoreW(addr, value, res);
912 if (res)
913 goto fault;
914 }
915 goto success;
916
917 case mm_ldm_func:
918#ifdef CONFIG_64BIT
919 reg = insn.mm_m_format.rd;
920 rvar = reg & 0xf;
921 if ((rvar > 9) || !reg)
922 goto sigill;
923 if (reg & 0x10) {
924 if (!access_ok
925 (VERIFY_READ, addr, 8 * (rvar + 1)))
926 goto sigbus;
927 } else {
928 if (!access_ok(VERIFY_READ, addr, 8 * rvar))
929 goto sigbus;
930 }
931 if (rvar == 9)
932 rvar = 8;
933
934 for (i = 16; rvar; rvar--, i++) {
935 LoadDW(addr, value, res);
936 if (res)
937 goto fault;
938 addr += 4;
939 regs->regs[i] = value;
940 }
941 if ((reg & 0xf) == 9) {
942 LoadDW(addr, value, res);
943 if (res)
944 goto fault;
945 addr += 8;
946 regs->regs[30] = value;
947 }
948 if (reg & 0x10) {
949 LoadDW(addr, value, res);
950 if (res)
951 goto fault;
952 regs->regs[31] = value;
953 }
954 goto success;
955#endif /* CONFIG_64BIT */
956
957 goto sigill;
958
959 case mm_sdm_func:
960#ifdef CONFIG_64BIT
961 reg = insn.mm_m_format.rd;
962 rvar = reg & 0xf;
963 if ((rvar > 9) || !reg)
964 goto sigill;
965 if (reg & 0x10) {
966 if (!access_ok
967 (VERIFY_WRITE, addr, 8 * (rvar + 1)))
968 goto sigbus;
969 } else {
970 if (!access_ok(VERIFY_WRITE, addr, 8 * rvar))
971 goto sigbus;
972 }
973 if (rvar == 9)
974 rvar = 8;
975
976 for (i = 16; rvar; rvar--, i++) {
977 value = regs->regs[i];
978 StoreDW(addr, value, res);
979 if (res)
980 goto fault;
981 addr += 8;
982 }
983 if ((reg & 0xf) == 9) {
984 value = regs->regs[30];
985 StoreDW(addr, value, res);
986 if (res)
987 goto fault;
988 addr += 8;
989 }
990 if (reg & 0x10) {
991 value = regs->regs[31];
992 StoreDW(addr, value, res);
993 if (res)
994 goto fault;
995 }
996 goto success;
997#endif /* CONFIG_64BIT */
998
999 goto sigill;
1000
1001 /* LWC2, SWC2, LDC2, SDC2 are not serviced */
1002 }
1003
1004 goto sigbus;
1005
1006 case mm_pool32c_op:
1007 switch (insn.mm_m_format.func) {
1008 case mm_lwu_func:
1009 reg = insn.mm_m_format.rd;
1010 goto loadWU;
1011 }
1012
1013 /* LL,SC,LLD,SCD are not serviced */
1014 goto sigbus;
1015
1016 case mm_pool32f_op:
1017 switch (insn.mm_x_format.func) {
1018 case mm_lwxc1_func:
1019 case mm_swxc1_func:
1020 case mm_ldxc1_func:
1021 case mm_sdxc1_func:
1022 goto fpu_emul;
1023 }
1024
1025 goto sigbus;
1026
1027 case mm_ldc132_op:
1028 case mm_sdc132_op:
1029 case mm_lwc132_op:
1030 case mm_swc132_op:
1031fpu_emul:
1032 /* roll back jump/branch */
1033 regs->cp0_epc = origpc;
1034 regs->regs[31] = orig31;
1035
1036 die_if_kernel("Unaligned FP access in kernel code", regs);
1037 BUG_ON(!used_math());
1038 BUG_ON(!is_fpu_owner());
1039
1040 lose_fpu(1); /* save the FPU state for the emulator */
1041 res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
1042 &fault_addr);
1043 own_fpu(1); /* restore FPU state */
1044
1045 /* If something went wrong, signal */
1046 process_fpemu_return(res, fault_addr);
1047
1048 if (res == 0)
1049 goto success;
1050 return;
1051
1052 case mm_lh32_op:
1053 reg = insn.mm_i_format.rt;
1054 goto loadHW;
1055
1056 case mm_lhu32_op:
1057 reg = insn.mm_i_format.rt;
1058 goto loadHWU;
1059
1060 case mm_lw32_op:
1061 reg = insn.mm_i_format.rt;
1062 goto loadW;
1063
1064 case mm_sh32_op:
1065 reg = insn.mm_i_format.rt;
1066 goto storeHW;
1067
1068 case mm_sw32_op:
1069 reg = insn.mm_i_format.rt;
1070 goto storeW;
1071
1072 case mm_ld32_op:
1073 reg = insn.mm_i_format.rt;
1074 goto loadDW;
1075
1076 case mm_sd32_op:
1077 reg = insn.mm_i_format.rt;
1078 goto storeDW;
1079
1080 case mm_pool16c_op:
1081 switch (insn.mm16_m_format.func) {
1082 case mm_lwm16_op:
1083 reg = insn.mm16_m_format.rlist;
1084 rvar = reg + 1;
1085 if (!access_ok(VERIFY_READ, addr, 4 * rvar))
1086 goto sigbus;
1087
1088 for (i = 16; rvar; rvar--, i++) {
1089 LoadW(addr, value, res);
1090 if (res)
1091 goto fault;
1092 addr += 4;
1093 regs->regs[i] = value;
1094 }
1095 LoadW(addr, value, res);
1096 if (res)
1097 goto fault;
1098 regs->regs[31] = value;
1099
1100 goto success;
1101
1102 case mm_swm16_op:
1103 reg = insn.mm16_m_format.rlist;
1104 rvar = reg + 1;
1105 if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
1106 goto sigbus;
1107
1108 for (i = 16; rvar; rvar--, i++) {
1109 value = regs->regs[i];
1110 StoreW(addr, value, res);
1111 if (res)
1112 goto fault;
1113 addr += 4;
1114 }
1115 value = regs->regs[31];
1116 StoreW(addr, value, res);
1117 if (res)
1118 goto fault;
1119
1120 goto success;
1121
1122 }
1123
1124 goto sigbus;
1125
1126 case mm_lhu16_op:
1127 reg = reg16to32[insn.mm16_rb_format.rt];
1128 goto loadHWU;
1129
1130 case mm_lw16_op:
1131 reg = reg16to32[insn.mm16_rb_format.rt];
1132 goto loadW;
1133
1134 case mm_sh16_op:
1135 reg = reg16to32st[insn.mm16_rb_format.rt];
1136 goto storeHW;
1137
1138 case mm_sw16_op:
1139 reg = reg16to32st[insn.mm16_rb_format.rt];
1140 goto storeW;
1141
1142 case mm_lwsp16_op:
1143 reg = insn.mm16_r5_format.rt;
1144 goto loadW;
1145
1146 case mm_swsp16_op:
1147 reg = insn.mm16_r5_format.rt;
1148 goto storeW;
1149
1150 case mm_lwgp16_op:
1151 reg = reg16to32[insn.mm16_r3_format.rt];
1152 goto loadW;
1153
1154 default:
1155 goto sigill;
1156 }
1157
1158loadHW:
1159 if (!access_ok(VERIFY_READ, addr, 2))
1160 goto sigbus;
1161
1162 LoadHW(addr, value, res);
1163 if (res)
1164 goto fault;
1165 regs->regs[reg] = value;
1166 goto success;
1167
1168loadHWU:
1169 if (!access_ok(VERIFY_READ, addr, 2))
1170 goto sigbus;
1171
1172 LoadHWU(addr, value, res);
1173 if (res)
1174 goto fault;
1175 regs->regs[reg] = value;
1176 goto success;
1177
1178loadW:
1179 if (!access_ok(VERIFY_READ, addr, 4))
1180 goto sigbus;
1181
1182 LoadW(addr, value, res);
1183 if (res)
1184 goto fault;
1185 regs->regs[reg] = value;
1186 goto success;
1187
1188loadWU:
1189#ifdef CONFIG_64BIT
1190 /*
1191 * A 32-bit kernel might be running on a 64-bit processor. But
1192 * if we're on a 32-bit processor and an i-cache incoherency
1193 * or race makes us see a 64-bit instruction here the sdl/sdr
1194 * would blow up, so for now we don't handle unaligned 64-bit
1195 * instructions on 32-bit kernels.
1196 */
1197 if (!access_ok(VERIFY_READ, addr, 4))
1198 goto sigbus;
1199
1200 LoadWU(addr, value, res);
1201 if (res)
1202 goto fault;
1203 regs->regs[reg] = value;
1204 goto success;
1205#endif /* CONFIG_64BIT */
1206
1207 /* Cannot handle 64-bit instructions in 32-bit kernel */
1208 goto sigill;
1209
1210loadDW:
1211#ifdef CONFIG_64BIT
1212 /*
1213 * A 32-bit kernel might be running on a 64-bit processor. But
1214 * if we're on a 32-bit processor and an i-cache incoherency
1215 * or race makes us see a 64-bit instruction here the sdl/sdr
1216 * would blow up, so for now we don't handle unaligned 64-bit
1217 * instructions on 32-bit kernels.
1218 */
1219 if (!access_ok(VERIFY_READ, addr, 8))
1220 goto sigbus;
1221
1222 LoadDW(addr, value, res);
1223 if (res)
1224 goto fault;
1225 regs->regs[reg] = value;
1226 goto success;
1227#endif /* CONFIG_64BIT */
1228
1229 /* Cannot handle 64-bit instructions in 32-bit kernel */
1230 goto sigill;
1231
1232storeHW:
1233 if (!access_ok(VERIFY_WRITE, addr, 2))
1234 goto sigbus;
1235
1236 value = regs->regs[reg];
1237 StoreHW(addr, value, res);
1238 if (res)
1239 goto fault;
1240 goto success;
1241
1242storeW:
1243 if (!access_ok(VERIFY_WRITE, addr, 4))
1244 goto sigbus;
1245
1246 value = regs->regs[reg];
1247 StoreW(addr, value, res);
1248 if (res)
1249 goto fault;
1250 goto success;
1251
1252storeDW:
1253#ifdef CONFIG_64BIT
1254 /*
1255 * A 32-bit kernel might be running on a 64-bit processor. But
1256 * if we're on a 32-bit processor and an i-cache incoherency
1257 * or race makes us see a 64-bit instruction here the sdl/sdr
1258 * would blow up, so for now we don't handle unaligned 64-bit
1259 * instructions on 32-bit kernels.
1260 */
1261 if (!access_ok(VERIFY_WRITE, addr, 8))
1262 goto sigbus;
1263
1264 value = regs->regs[reg];
1265 StoreDW(addr, value, res);
1266 if (res)
1267 goto fault;
1268 goto success;
1269#endif /* CONFIG_64BIT */
1270
1271 /* Cannot handle 64-bit instructions in 32-bit kernel */
1272 goto sigill;
1273
1274success:
1275 regs->cp0_epc = contpc; /* advance or branch */
1276
1277#ifdef CONFIG_DEBUG_FS
1278 unaligned_instructions++;
1279#endif
1280 return;
1281
1282fault:
1283 /* roll back jump/branch */
1284 regs->cp0_epc = origpc;
1285 regs->regs[31] = orig31;
505 /* Did we have an exception handler installed? */ 1286 /* Did we have an exception handler installed? */
506 if (fixup_exception(regs)) 1287 if (fixup_exception(regs))
507 return; 1288 return;
@@ -518,7 +1299,8 @@ sigbus:
518 return; 1299 return;
519 1300
520sigill: 1301sigill:
521 die_if_kernel("Unhandled kernel unaligned access or invalid instruction", regs); 1302 die_if_kernel
1303 ("Unhandled kernel unaligned access or invalid instruction", regs);
522 force_sig(SIGILL, current); 1304 force_sig(SIGILL, current);
523} 1305}
524 1306
@@ -531,23 +1313,51 @@ asmlinkage void do_ade(struct pt_regs *regs)
531 1, regs, regs->cp0_badvaddr); 1313 1, regs, regs->cp0_badvaddr);
532 /* 1314 /*
533 * Did we catch a fault trying to load an instruction? 1315 * Did we catch a fault trying to load an instruction?
534 * Or are we running in MIPS16 mode?
535 */ 1316 */
536 if ((regs->cp0_badvaddr == regs->cp0_epc) || (regs->cp0_epc & 0x1)) 1317 if (regs->cp0_badvaddr == regs->cp0_epc)
537 goto sigbus; 1318 goto sigbus;
538 1319
539 pc = (unsigned int __user *) exception_epc(regs);
540 if (user_mode(regs) && !test_thread_flag(TIF_FIXADE)) 1320 if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
541 goto sigbus; 1321 goto sigbus;
542 if (unaligned_action == UNALIGNED_ACTION_SIGNAL) 1322 if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
543 goto sigbus; 1323 goto sigbus;
544 else if (unaligned_action == UNALIGNED_ACTION_SHOW)
545 show_registers(regs);
546 1324
547 /* 1325 /*
548 * Do branch emulation only if we didn't forward the exception. 1326 * Do branch emulation only if we didn't forward the exception.
549 * This is all so but ugly ... 1327 * This is all so but ugly ...
550 */ 1328 */
1329
1330 /*
1331 * Are we running in microMIPS mode?
1332 */
1333 if (get_isa16_mode(regs->cp0_epc)) {
1334 /*
1335 * Did we catch a fault trying to load an instruction in
1336 * 16-bit mode?
1337 */
1338 if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
1339 goto sigbus;
1340 if (unaligned_action == UNALIGNED_ACTION_SHOW)
1341 show_registers(regs);
1342
1343 if (cpu_has_mmips) {
1344 seg = get_fs();
1345 if (!user_mode(regs))
1346 set_fs(KERNEL_DS);
1347 emulate_load_store_microMIPS(regs,
1348 (void __user *)regs->cp0_badvaddr);
1349 set_fs(seg);
1350
1351 return;
1352 }
1353
1354 goto sigbus;
1355 }
1356
1357 if (unaligned_action == UNALIGNED_ACTION_SHOW)
1358 show_registers(regs);
1359 pc = (unsigned int __user *)exception_epc(regs);
1360
551 seg = get_fs(); 1361 seg = get_fs();
552 if (!user_mode(regs)) 1362 if (!user_mode(regs))
553 set_fs(KERNEL_DS); 1363 set_fs(KERNEL_DS);