Skip to content

Commit 34c2f66

Browse files
Leonid Yegoshinralfbaechle
authored andcommitted
MIPS: microMIPS: Add unaligned access support.
Add logic needed to handle unaligned accesses in microMIPS mode. Signed-off-by: Steven J. Hill <[email protected]> Signed-off-by: Leonid Yegoshin <[email protected]>
1 parent fb6883e commit 34c2f66

File tree

2 files changed

+1112
-201
lines changed

2 files changed

+1112
-201
lines changed

arch/mips/kernel/process.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Copyright (C) 2005, 2006 by Ralf Baechle ([email protected])
88
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
99
* Copyright (C) 2004 Thiemo Seufer
10+
* Copyright (C) 2013 Imagination Technologies Ltd.
1011
*/
1112
#include <linux/errno.h>
1213
#include <linux/sched.h>
@@ -243,34 +244,115 @@ struct mips_frame_info {
243244

244245
static inline int is_ra_save_ins(union mips_instruction *ip)
245246
{
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
246278
/* sw / sd $ra, offset($sp) */
247279
return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
248280
ip->i_format.rs == 29 &&
249281
ip->i_format.rt == 31;
282+
#endif
250283
}
251284

252285
static inline int is_jal_jalr_jr_ins(union mips_instruction *ip)
253286
{
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
254309
if (ip->j_format.opcode == jal_op)
255310
return 1;
256311
if (ip->r_format.opcode != spec_op)
257312
return 0;
258313
return ip->r_format.func == jalr_op || ip->r_format.func == jr_op;
314+
#endif
259315
}
260316

261317
static inline int is_sp_move_ins(union mips_instruction *ip)
262318
{
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
263340
/* addiu/daddiu sp,sp,-imm */
264341
if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
265342
return 0;
266343
if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
267344
return 1;
345+
#endif
268346
return 0;
269347
}
270348

271349
static int get_frame_info(struct mips_frame_info *info)
272350
{
351+
#ifdef CONFIG_CPU_MICROMIPS
352+
union mips_instruction *ip = (void *) (((char *) info->func) - 1);
353+
#else
273354
union mips_instruction *ip = info->func;
355+
#endif
274356
unsigned max_insns = info->func_size / sizeof(union mips_instruction);
275357
unsigned i;
276358

@@ -290,7 +372,26 @@ static int get_frame_info(struct mips_frame_info *info)
290372
break;
291373
if (!info->frame_size) {
292374
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
293393
info->frame_size = - ip->i_format.simmediate;
394+
}
294395
continue;
295396
}
296397
if (info->pc_offset == -1 && is_ra_save_ins(ip)) {

0 commit comments

Comments
 (0)