MN10300: Perform misalignment fixups of MOV_Lcc

Perform misalignment fixups of the MOV_Lcc instructions (move postinc memory
to register and conditionally loop).

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by David Howells and committed by Linus Torvalds ddb6d05c aefefbbe

+94 -1
+94 -1
arch/mn10300/mm/misalignment.c
··· 50 50 unsigned opcode, unsigned long disp, 51 51 unsigned long **_register); 52 52 53 + static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode); 54 + 53 55 static const unsigned Dreg_index[] = { 54 56 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2 55 57 }; ··· 80 78 FMT_D7, 81 79 FMT_D8, 82 80 FMT_D9, 81 + FMT_D10, 83 82 }; 84 83 85 84 static const struct { ··· 98 95 [FMT_D7] = { 24, 8 }, 99 96 [FMT_D8] = { 24, 24 }, 100 97 [FMT_D9] = { 24, 32 }, 98 + [FMT_D10] = { 32, 0 }, 101 99 }; 102 100 103 101 enum value_id { ··· 297 293 { "movhu", 0xfeda0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, SP)}}, 298 294 { "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}}, 299 295 { "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}}, 296 + 297 + { "mov_llt", 0xf7e00000, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 298 + { "mov_lgt", 0xf7e00001, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 299 + { "mov_lge", 0xf7e00002, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 300 + { "mov_lle", 0xf7e00003, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 301 + { "mov_lcs", 0xf7e00004, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 302 + { "mov_lhi", 0xf7e00005, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 303 + { "mov_lcc", 0xf7e00006, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 304 + { "mov_lls", 0xf7e00007, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 305 + { "mov_leq", 0xf7e00008, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 306 + { "mov_lne", 0xf7e00009, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 307 + { "mov_lra", 0xf7e0000a, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 308 + 300 309 { 0, 0, 0, 0, 0, 0, {0}}, 301 310 }; 302 311 ··· 494 477 &store)) 495 478 goto bad_reg_mode; 496 479 497 - if (strcmp(pop->name, "mov") == 0) { 480 + if (strcmp(pop->name, "mov") == 0 || 481 + memcmp(pop->name, "mov_l", 5) == 0) { 498 482 kdebug("mov (%p),DARn", address); 499 483 if (copy_from_user(&data, (void *) address, 4) != 0) 500 484 goto transfer_failed; ··· 513 495 } 514 496 515 497 *store = data; 498 + kdebug("loaded %lx", data); 516 499 } else { 517 500 /* move register to memory */ 518 501 if (!misalignment_reg(registers, pop->params[0], opcode, disp, ··· 545 526 546 527 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz; 547 528 regs->pc += tmp >> 3; 529 + 530 + /* handle MOV_Lcc, which are currently the only FMT_D10 insns that 531 + * access memory */ 532 + if (pop->format == FMT_D10) 533 + misalignment_MOV_Lcc(regs, opcode); 548 534 549 535 set_fs(seg); 550 536 return; ··· 724 700 } 725 701 726 702 return 1; 703 + } 704 + 705 + /* 706 + * handle the conditional loop part of the move-and-loop instructions 707 + */ 708 + static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode) 709 + { 710 + unsigned long epsw = regs->epsw; 711 + unsigned long NxorV; 712 + 713 + kdebug("MOV_Lcc %x [flags=%lx]", opcode, epsw & 0xf); 714 + 715 + /* calculate N^V and shift onto the same bit position as Z */ 716 + NxorV = ((epsw >> 3) ^ epsw >> 1) & 1; 717 + 718 + switch (opcode & 0xf) { 719 + case 0x0: /* MOV_LLT: N^V */ 720 + if (NxorV) 721 + goto take_the_loop; 722 + return; 723 + case 0x1: /* MOV_LGT: ~(Z or (N^V))*/ 724 + if (!((epsw & EPSW_FLAG_Z) | NxorV)) 725 + goto take_the_loop; 726 + return; 727 + case 0x2: /* MOV_LGE: ~(N^V) */ 728 + if (!NxorV) 729 + goto take_the_loop; 730 + return; 731 + case 0x3: /* MOV_LLE: Z or (N^V) */ 732 + if ((epsw & EPSW_FLAG_Z) | NxorV) 733 + goto take_the_loop; 734 + return; 735 + 736 + case 0x4: /* MOV_LCS: C */ 737 + if (epsw & EPSW_FLAG_C) 738 + goto take_the_loop; 739 + return; 740 + case 0x5: /* MOV_LHI: ~(C or Z) */ 741 + if (!(epsw & (EPSW_FLAG_C | EPSW_FLAG_Z))) 742 + goto take_the_loop; 743 + return; 744 + case 0x6: /* MOV_LCC: ~C */ 745 + if (!(epsw & EPSW_FLAG_C)) 746 + goto take_the_loop; 747 + return; 748 + case 0x7: /* MOV_LLS: C or Z */ 749 + if (epsw & (EPSW_FLAG_C | EPSW_FLAG_Z)) 750 + goto take_the_loop; 751 + return; 752 + 753 + case 0x8: /* MOV_LEQ: Z */ 754 + if (epsw & EPSW_FLAG_Z) 755 + goto take_the_loop; 756 + return; 757 + case 0x9: /* MOV_LNE: ~Z */ 758 + if (!(epsw & EPSW_FLAG_Z)) 759 + goto take_the_loop; 760 + return; 761 + case 0xa: /* MOV_LRA: always */ 762 + goto take_the_loop; 763 + 764 + default: 765 + BUG(); 766 + } 767 + 768 + take_the_loop: 769 + /* wind the PC back to just after the SETLB insn */ 770 + kdebug("loop LAR=%lx", regs->lar); 771 + regs->pc = regs->lar - 4; 727 772 } 728 773 729 774 /*