aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-12 10:35:30 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-11-12 13:41:17 -0500
commitddb6d05cbaea76eddbee52585152ab801a8aedc7 (patch)
tree3cc3b24f10c608d2a228833dc4f0e8fab5fe689d
parentaefefbbec1ad25bafa97a7a1db25313ce26563e2 (diff)
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>
-rw-r--r--arch/mn10300/mm/misalignment.c95
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
53static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode);
54
53static const unsigned Dreg_index[] = { 55static 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
83static const struct { 86static 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
100enum value_id { 104enum 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 */
732static 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
792take_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