diff options
| -rw-r--r-- | arch/mn10300/mm/misalignment.c | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c index 05a3c2f8d2df..d5b45bb7d108 100644 --- a/arch/mn10300/mm/misalignment.c +++ b/arch/mn10300/mm/misalignment.c | |||
| @@ -50,6 +50,8 @@ static int misalignment_reg(unsigned long *registers, unsigned params, | |||
| 50 | unsigned opcode, unsigned long disp, | 50 | unsigned opcode, unsigned long disp, |
| 51 | unsigned long **_register); | 51 | unsigned long **_register); |
| 52 | 52 | ||
| 53 | static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode); | ||
| 54 | |||
| 53 | static const unsigned Dreg_index[] = { | 55 | static const unsigned Dreg_index[] = { |
| 54 | REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2 | 56 | REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2 |
| 55 | }; | 57 | }; |
| @@ -78,6 +80,7 @@ enum format_id { | |||
| 78 | FMT_D7, | 80 | FMT_D7, |
| 79 | FMT_D8, | 81 | FMT_D8, |
| 80 | FMT_D9, | 82 | FMT_D9, |
| 83 | FMT_D10, | ||
| 81 | }; | 84 | }; |
| 82 | 85 | ||
| 83 | static const struct { | 86 | static const struct { |
| @@ -95,6 +98,7 @@ static const struct { | |||
| 95 | [FMT_D7] = { 24, 8 }, | 98 | [FMT_D7] = { 24, 8 }, |
| 96 | [FMT_D8] = { 24, 24 }, | 99 | [FMT_D8] = { 24, 24 }, |
| 97 | [FMT_D9] = { 24, 32 }, | 100 | [FMT_D9] = { 24, 32 }, |
| 101 | [FMT_D10] = { 32, 0 }, | ||
| 98 | }; | 102 | }; |
| 99 | 103 | ||
| 100 | enum value_id { | 104 | enum value_id { |
| @@ -293,6 +297,19 @@ static const struct mn10300_opcode mn10300_opcodes[] = { | |||
| 293 | { "movhu", 0xfeda0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, SP)}}, | 297 | { "movhu", 0xfeda0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, SP)}}, |
| 294 | { "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}}, | 298 | { "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}}, |
| 295 | { "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}}, | 299 | { "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}}, |
| 300 | |||
| 301 | { "mov_llt", 0xf7e00000, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 302 | { "mov_lgt", 0xf7e00001, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 303 | { "mov_lge", 0xf7e00002, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 304 | { "mov_lle", 0xf7e00003, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 305 | { "mov_lcs", 0xf7e00004, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 306 | { "mov_lhi", 0xf7e00005, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 307 | { "mov_lcc", 0xf7e00006, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 308 | { "mov_lls", 0xf7e00007, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 309 | { "mov_leq", 0xf7e00008, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 310 | { "mov_lne", 0xf7e00009, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 311 | { "mov_lra", 0xf7e0000a, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, | ||
| 312 | |||
| 296 | { 0, 0, 0, 0, 0, 0, {0}}, | 313 | { 0, 0, 0, 0, 0, 0, {0}}, |
| 297 | }; | 314 | }; |
| 298 | 315 | ||
| @@ -477,7 +494,8 @@ found_opcode: | |||
| 477 | &store)) | 494 | &store)) |
| 478 | goto bad_reg_mode; | 495 | goto bad_reg_mode; |
| 479 | 496 | ||
| 480 | if (strcmp(pop->name, "mov") == 0) { | 497 | if (strcmp(pop->name, "mov") == 0 || |
| 498 | memcmp(pop->name, "mov_l", 5) == 0) { | ||
| 481 | kdebug("mov (%p),DARn", address); | 499 | kdebug("mov (%p),DARn", address); |
| 482 | if (copy_from_user(&data, (void *) address, 4) != 0) | 500 | if (copy_from_user(&data, (void *) address, 4) != 0) |
| 483 | goto transfer_failed; | 501 | goto transfer_failed; |
| @@ -495,6 +513,7 @@ found_opcode: | |||
| 495 | } | 513 | } |
| 496 | 514 | ||
| 497 | *store = data; | 515 | *store = data; |
| 516 | kdebug("loaded %lx", data); | ||
| 498 | } else { | 517 | } else { |
| 499 | /* move register to memory */ | 518 | /* move register to memory */ |
| 500 | if (!misalignment_reg(registers, pop->params[0], opcode, disp, | 519 | if (!misalignment_reg(registers, pop->params[0], opcode, disp, |
| @@ -527,6 +546,11 @@ found_opcode: | |||
| 527 | tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz; | 546 | tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz; |
| 528 | regs->pc += tmp >> 3; | 547 | regs->pc += tmp >> 3; |
| 529 | 548 | ||
| 549 | /* handle MOV_Lcc, which are currently the only FMT_D10 insns that | ||
| 550 | * access memory */ | ||
| 551 | if (pop->format == FMT_D10) | ||
| 552 | misalignment_MOV_Lcc(regs, opcode); | ||
| 553 | |||
| 530 | set_fs(seg); | 554 | set_fs(seg); |
| 531 | return; | 555 | return; |
| 532 | } | 556 | } |
| @@ -703,6 +727,75 @@ static int misalignment_reg(unsigned long *registers, unsigned params, | |||
| 703 | } | 727 | } |
| 704 | 728 | ||
| 705 | /* | 729 | /* |
| 730 | * handle the conditional loop part of the move-and-loop instructions | ||
| 731 | */ | ||
| 732 | static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode) | ||
| 733 | { | ||
| 734 | unsigned long epsw = regs->epsw; | ||
| 735 | unsigned long NxorV; | ||
| 736 | |||
| 737 | kdebug("MOV_Lcc %x [flags=%lx]", opcode, epsw & 0xf); | ||
| 738 | |||
| 739 | /* calculate N^V and shift onto the same bit position as Z */ | ||
| 740 | NxorV = ((epsw >> 3) ^ epsw >> 1) & 1; | ||
| 741 | |||
| 742 | switch (opcode & 0xf) { | ||
| 743 | case 0x0: /* MOV_LLT: N^V */ | ||
| 744 | if (NxorV) | ||
| 745 | goto take_the_loop; | ||
| 746 | return; | ||
| 747 | case 0x1: /* MOV_LGT: ~(Z or (N^V))*/ | ||
| 748 | if (!((epsw & EPSW_FLAG_Z) | NxorV)) | ||
| 749 | goto take_the_loop; | ||
| 750 | return; | ||
| 751 | case 0x2: /* MOV_LGE: ~(N^V) */ | ||
| 752 | if (!NxorV) | ||
| 753 | goto take_the_loop; | ||
| 754 | return; | ||
| 755 | case 0x3: /* MOV_LLE: Z or (N^V) */ | ||
| 756 | if ((epsw & EPSW_FLAG_Z) | NxorV) | ||
| 757 | goto take_the_loop; | ||
| 758 | return; | ||
| 759 | |||
| 760 | case 0x4: /* MOV_LCS: C */ | ||
| 761 | if (epsw & EPSW_FLAG_C) | ||
| 762 | goto take_the_loop; | ||
| 763 | return; | ||
| 764 | case 0x5: /* MOV_LHI: ~(C or Z) */ | ||
| 765 | if (!(epsw & (EPSW_FLAG_C | EPSW_FLAG_Z))) | ||
| 766 | goto take_the_loop; | ||
| 767 | return; | ||
| 768 | case 0x6: /* MOV_LCC: ~C */ | ||
| 769 | if (!(epsw & EPSW_FLAG_C)) | ||
| 770 | goto take_the_loop; | ||
| 771 | return; | ||
| 772 | case 0x7: /* MOV_LLS: C or Z */ | ||
| 773 | if (epsw & (EPSW_FLAG_C | EPSW_FLAG_Z)) | ||
| 774 | goto take_the_loop; | ||
| 775 | return; | ||
| 776 | |||
| 777 | case 0x8: /* MOV_LEQ: Z */ | ||
| 778 | if (epsw & EPSW_FLAG_Z) | ||
| 779 | goto take_the_loop; | ||
| 780 | return; | ||
| 781 | case 0x9: /* MOV_LNE: ~Z */ | ||
| 782 | if (!(epsw & EPSW_FLAG_Z)) | ||
| 783 | goto take_the_loop; | ||
| 784 | return; | ||
| 785 | case 0xa: /* MOV_LRA: always */ | ||
| 786 | goto take_the_loop; | ||
| 787 | |||
| 788 | default: | ||
| 789 | BUG(); | ||
| 790 | } | ||
| 791 | |||
| 792 | take_the_loop: | ||
| 793 | /* wind the PC back to just after the SETLB insn */ | ||
| 794 | kdebug("loop LAR=%lx", regs->lar); | ||
| 795 | regs->pc = regs->lar - 4; | ||
| 796 | } | ||
| 797 | |||
| 798 | /* | ||
| 706 | * misalignment handler tests | 799 | * misalignment handler tests |
| 707 | */ | 800 | */ |
| 708 | #ifdef CONFIG_TEST_MISALIGNMENT_HANDLER | 801 | #ifdef CONFIG_TEST_MISALIGNMENT_HANDLER |
