aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/process.c')
-rw-r--r--arch/mips/kernel/process.c102
1 files changed, 61 insertions, 41 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 5351e1f3950d..c5ff6bfe2825 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -208,13 +208,13 @@ static inline int is_ra_save_ins(union mips_instruction *ip, int *poff)
208 * 208 *
209 * microMIPS is way more fun... 209 * microMIPS is way more fun...
210 */ 210 */
211 if (mm_insn_16bit(ip->halfword[1])) { 211 if (mm_insn_16bit(ip->word >> 16)) {
212 switch (ip->mm16_r5_format.opcode) { 212 switch (ip->mm16_r5_format.opcode) {
213 case mm_swsp16_op: 213 case mm_swsp16_op:
214 if (ip->mm16_r5_format.rt != 31) 214 if (ip->mm16_r5_format.rt != 31)
215 return 0; 215 return 0;
216 216
217 *poff = ip->mm16_r5_format.simmediate; 217 *poff = ip->mm16_r5_format.imm;
218 *poff = (*poff << 2) / sizeof(ulong); 218 *poff = (*poff << 2) / sizeof(ulong);
219 return 1; 219 return 1;
220 220
@@ -287,7 +287,7 @@ static inline int is_jump_ins(union mips_instruction *ip)
287 * 287 *
288 * microMIPS is kind of more fun... 288 * microMIPS is kind of more fun...
289 */ 289 */
290 if (mm_insn_16bit(ip->halfword[1])) { 290 if (mm_insn_16bit(ip->word >> 16)) {
291 if ((ip->mm16_r5_format.opcode == mm_pool16c_op && 291 if ((ip->mm16_r5_format.opcode == mm_pool16c_op &&
292 (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op)) 292 (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op))
293 return 1; 293 return 1;
@@ -313,9 +313,11 @@ static inline int is_jump_ins(union mips_instruction *ip)
313#endif 313#endif
314} 314}
315 315
316static inline int is_sp_move_ins(union mips_instruction *ip) 316static inline int is_sp_move_ins(union mips_instruction *ip, int *frame_size)
317{ 317{
318#ifdef CONFIG_CPU_MICROMIPS 318#ifdef CONFIG_CPU_MICROMIPS
319 unsigned short tmp;
320
319 /* 321 /*
320 * addiusp -imm 322 * addiusp -imm
321 * addius5 sp,-imm 323 * addius5 sp,-imm
@@ -324,21 +326,40 @@ static inline int is_sp_move_ins(union mips_instruction *ip)
324 * 326 *
325 * microMIPS is not more fun... 327 * microMIPS is not more fun...
326 */ 328 */
327 if (mm_insn_16bit(ip->halfword[1])) { 329 if (mm_insn_16bit(ip->word >> 16)) {
328 return (ip->mm16_r3_format.opcode == mm_pool16d_op && 330 if (ip->mm16_r3_format.opcode == mm_pool16d_op &&
329 ip->mm16_r3_format.simmediate && mm_addiusp_func) || 331 ip->mm16_r3_format.simmediate & mm_addiusp_func) {
330 (ip->mm16_r5_format.opcode == mm_pool16d_op && 332 tmp = ip->mm_b0_format.simmediate >> 1;
331 ip->mm16_r5_format.rt == 29); 333 tmp = ((tmp & 0x1ff) ^ 0x100) - 0x100;
334 if ((tmp + 2) < 4) /* 0x0,0x1,0x1fe,0x1ff are special */
335 tmp ^= 0x100;
336 *frame_size = -(signed short)(tmp << 2);
337 return 1;
338 }
339 if (ip->mm16_r5_format.opcode == mm_pool16d_op &&
340 ip->mm16_r5_format.rt == 29) {
341 tmp = ip->mm16_r5_format.imm >> 1;
342 *frame_size = -(signed short)(tmp & 0xf);
343 return 1;
344 }
345 return 0;
332 } 346 }
333 347
334 return ip->mm_i_format.opcode == mm_addiu32_op && 348 if (ip->mm_i_format.opcode == mm_addiu32_op &&
335 ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29; 349 ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29) {
350 *frame_size = -ip->i_format.simmediate;
351 return 1;
352 }
336#else 353#else
337 /* addiu/daddiu sp,sp,-imm */ 354 /* addiu/daddiu sp,sp,-imm */
338 if (ip->i_format.rs != 29 || ip->i_format.rt != 29) 355 if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
339 return 0; 356 return 0;
340 if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) 357
358 if (ip->i_format.opcode == addiu_op ||
359 ip->i_format.opcode == daddiu_op) {
360 *frame_size = -ip->i_format.simmediate;
341 return 1; 361 return 1;
362 }
342#endif 363#endif
343 return 0; 364 return 0;
344} 365}
@@ -348,7 +369,9 @@ static int get_frame_info(struct mips_frame_info *info)
348 bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS); 369 bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS);
349 union mips_instruction insn, *ip, *ip_end; 370 union mips_instruction insn, *ip, *ip_end;
350 const unsigned int max_insns = 128; 371 const unsigned int max_insns = 128;
372 unsigned int last_insn_size = 0;
351 unsigned int i; 373 unsigned int i;
374 bool saw_jump = false;
352 375
353 info->pc_offset = -1; 376 info->pc_offset = -1;
354 info->frame_size = 0; 377 info->frame_size = 0;
@@ -359,47 +382,44 @@ static int get_frame_info(struct mips_frame_info *info)
359 382
360 ip_end = (void *)ip + info->func_size; 383 ip_end = (void *)ip + info->func_size;
361 384
362 for (i = 0; i < max_insns && ip < ip_end; i++, ip++) { 385 for (i = 0; i < max_insns && ip < ip_end; i++) {
386 ip = (void *)ip + last_insn_size;
363 if (is_mmips && mm_insn_16bit(ip->halfword[0])) { 387 if (is_mmips && mm_insn_16bit(ip->halfword[0])) {
364 insn.halfword[0] = 0; 388 insn.word = ip->halfword[0] << 16;
365 insn.halfword[1] = ip->halfword[0]; 389 last_insn_size = 2;
366 } else if (is_mmips) { 390 } else if (is_mmips) {
367 insn.halfword[0] = ip->halfword[1]; 391 insn.word = ip->halfword[0] << 16 | ip->halfword[1];
368 insn.halfword[1] = ip->halfword[0]; 392 last_insn_size = 4;
369 } else { 393 } else {
370 insn.word = ip->word; 394 insn.word = ip->word;
395 last_insn_size = 4;
371 } 396 }
372 397
373 if (is_jump_ins(&insn))
374 break;
375
376 if (!info->frame_size) { 398 if (!info->frame_size) {
377 if (is_sp_move_ins(&insn)) 399 is_sp_move_ins(&insn, &info->frame_size);
378 { 400 continue;
379#ifdef CONFIG_CPU_MICROMIPS 401 } else if (!saw_jump && is_jump_ins(ip)) {
380 if (mm_insn_16bit(ip->halfword[0])) 402 /*
381 { 403 * If we see a jump instruction, we are finished
382 unsigned short tmp; 404 * with the frame save.
383 405 *
384 if (ip->halfword[0] & mm_addiusp_func) 406 * Some functions can have a shortcut return at
385 { 407 * the beginning of the function, so don't start
386 tmp = (((ip->halfword[0] >> 1) & 0x1ff) << 2); 408 * looking for jump instruction until we see the
387 info->frame_size = -(signed short)(tmp | ((tmp & 0x100) ? 0xfe00 : 0)); 409 * frame setup.
388 } else { 410 *
389 tmp = (ip->halfword[0] >> 1); 411 * The RA save instruction can get put into the
390 info->frame_size = -(signed short)(tmp & 0xf); 412 * delay slot of the jump instruction, so look
391 } 413 * at the next instruction, too.
392 ip = (void *) &ip->halfword[1]; 414 */
393 ip--; 415 saw_jump = true;
394 } else
395#endif
396 info->frame_size = - ip->i_format.simmediate;
397 }
398 continue; 416 continue;
399 } 417 }
400 if (info->pc_offset == -1 && 418 if (info->pc_offset == -1 &&
401 is_ra_save_ins(&insn, &info->pc_offset)) 419 is_ra_save_ins(&insn, &info->pc_offset))
402 break; 420 break;
421 if (saw_jump)
422 break;
403 } 423 }
404 if (info->frame_size && info->pc_offset >= 0) /* nested */ 424 if (info->frame_size && info->pc_offset >= 0) /* nested */
405 return 0; 425 return 0;