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 05a3c2f8d2d..d5b45bb7d10 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 |