Commit ddb6d05c authored by David Howells's avatar David Howells Committed by Linus Torvalds

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: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent aefefbbe
...@@ -50,6 +50,8 @@ static int misalignment_reg(unsigned long *registers, unsigned params, ...@@ -50,6 +50,8 @@ static int misalignment_reg(unsigned long *registers, unsigned params,
unsigned opcode, unsigned long disp, unsigned opcode, unsigned long disp,
unsigned long **_register); unsigned long **_register);
static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode);
static const unsigned Dreg_index[] = { static const unsigned Dreg_index[] = {
REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
}; };
...@@ -78,6 +80,7 @@ enum format_id { ...@@ -78,6 +80,7 @@ enum format_id {
FMT_D7, FMT_D7,
FMT_D8, FMT_D8,
FMT_D9, FMT_D9,
FMT_D10,
}; };
static const struct { static const struct {
...@@ -95,6 +98,7 @@ static const struct { ...@@ -95,6 +98,7 @@ static const struct {
[FMT_D7] = { 24, 8 }, [FMT_D7] = { 24, 8 },
[FMT_D8] = { 24, 24 }, [FMT_D8] = { 24, 24 },
[FMT_D9] = { 24, 32 }, [FMT_D9] = { 24, 32 },
[FMT_D10] = { 32, 0 },
}; };
enum value_id { enum value_id {
...@@ -293,6 +297,19 @@ static const struct mn10300_opcode mn10300_opcodes[] = { ...@@ -293,6 +297,19 @@ static const struct mn10300_opcode mn10300_opcodes[] = {
{ "movhu", 0xfeda0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, SP)}}, { "movhu", 0xfeda0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, SP)}},
{ "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}}, { "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
{ "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}}, { "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
{ "mov_llt", 0xf7e00000, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_lgt", 0xf7e00001, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_lge", 0xf7e00002, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_lle", 0xf7e00003, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_lcs", 0xf7e00004, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_lhi", 0xf7e00005, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_lcc", 0xf7e00006, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_lls", 0xf7e00007, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_leq", 0xf7e00008, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_lne", 0xf7e00009, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ "mov_lra", 0xf7e0000a, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}},
{ 0, 0, 0, 0, 0, 0, {0}}, { 0, 0, 0, 0, 0, 0, {0}},
}; };
...@@ -477,7 +494,8 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) ...@@ -477,7 +494,8 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
&store)) &store))
goto bad_reg_mode; goto bad_reg_mode;
if (strcmp(pop->name, "mov") == 0) { if (strcmp(pop->name, "mov") == 0 ||
memcmp(pop->name, "mov_l", 5) == 0) {
kdebug("mov (%p),DARn", address); kdebug("mov (%p),DARn", address);
if (copy_from_user(&data, (void *) address, 4) != 0) if (copy_from_user(&data, (void *) address, 4) != 0)
goto transfer_failed; goto transfer_failed;
...@@ -495,6 +513,7 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) ...@@ -495,6 +513,7 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
} }
*store = data; *store = data;
kdebug("loaded %lx", data);
} else { } else {
/* move register to memory */ /* move register to memory */
if (!misalignment_reg(registers, pop->params[0], opcode, disp, if (!misalignment_reg(registers, pop->params[0], opcode, disp,
...@@ -527,6 +546,11 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) ...@@ -527,6 +546,11 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz; tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz;
regs->pc += tmp >> 3; regs->pc += tmp >> 3;
/* handle MOV_Lcc, which are currently the only FMT_D10 insns that
* access memory */
if (pop->format == FMT_D10)
misalignment_MOV_Lcc(regs, opcode);
set_fs(seg); set_fs(seg);
return; return;
} }
...@@ -702,6 +726,75 @@ static int misalignment_reg(unsigned long *registers, unsigned params, ...@@ -702,6 +726,75 @@ static int misalignment_reg(unsigned long *registers, unsigned params,
return 1; return 1;
} }
/*
* handle the conditional loop part of the move-and-loop instructions
*/
static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode)
{
unsigned long epsw = regs->epsw;
unsigned long NxorV;
kdebug("MOV_Lcc %x [flags=%lx]", opcode, epsw & 0xf);
/* calculate N^V and shift onto the same bit position as Z */
NxorV = ((epsw >> 3) ^ epsw >> 1) & 1;
switch (opcode & 0xf) {
case 0x0: /* MOV_LLT: N^V */
if (NxorV)
goto take_the_loop;
return;
case 0x1: /* MOV_LGT: ~(Z or (N^V))*/
if (!((epsw & EPSW_FLAG_Z) | NxorV))
goto take_the_loop;
return;
case 0x2: /* MOV_LGE: ~(N^V) */
if (!NxorV)
goto take_the_loop;
return;
case 0x3: /* MOV_LLE: Z or (N^V) */
if ((epsw & EPSW_FLAG_Z) | NxorV)
goto take_the_loop;
return;
case 0x4: /* MOV_LCS: C */
if (epsw & EPSW_FLAG_C)
goto take_the_loop;
return;
case 0x5: /* MOV_LHI: ~(C or Z) */
if (!(epsw & (EPSW_FLAG_C | EPSW_FLAG_Z)))
goto take_the_loop;
return;
case 0x6: /* MOV_LCC: ~C */
if (!(epsw & EPSW_FLAG_C))
goto take_the_loop;
return;
case 0x7: /* MOV_LLS: C or Z */
if (epsw & (EPSW_FLAG_C | EPSW_FLAG_Z))
goto take_the_loop;
return;
case 0x8: /* MOV_LEQ: Z */
if (epsw & EPSW_FLAG_Z)
goto take_the_loop;
return;
case 0x9: /* MOV_LNE: ~Z */
if (!(epsw & EPSW_FLAG_Z))
goto take_the_loop;
return;
case 0xa: /* MOV_LRA: always */
goto take_the_loop;
default:
BUG();
}
take_the_loop:
/* wind the PC back to just after the SETLB insn */
kdebug("loop LAR=%lx", regs->lar);
regs->pc = regs->lar - 4;
}
/* /*
* misalignment handler tests * misalignment handler tests
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment