aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/process.c
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 /arch/mips/kernel/process.c
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>
Diffstat (limited to 'arch/mips/kernel/process.c')
-rw-r--r--arch/mips/kernel/process.c101
1 files changed, 101 insertions, 0 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)) {