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

MN10300: Handle misaligned SP-based operands

Support misalignment handling for instructions that have kernel SP-based
address operands, including fixing those that include IMM8 or IMM16
displacements.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 852c15b7
...@@ -42,8 +42,9 @@ ...@@ -42,8 +42,9 @@
#define kdebug(FMT, ...) do {} while (0) #define kdebug(FMT, ...) do {} while (0)
#endif #endif
static int misalignment_addr(unsigned long *registers, unsigned params, static int misalignment_addr(unsigned long *registers, unsigned long sp,
unsigned opcode, unsigned long disp, unsigned params, unsigned opcode,
unsigned long disp,
void **_address, unsigned long **_postinc, void **_address, unsigned long **_postinc,
unsigned long *_inc); unsigned long *_inc);
...@@ -322,7 +323,7 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) ...@@ -322,7 +323,7 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
const struct exception_table_entry *fixup; const struct exception_table_entry *fixup;
const struct mn10300_opcode *pop; const struct mn10300_opcode *pop;
unsigned long *registers = (unsigned long *) regs; unsigned long *registers = (unsigned long *) regs;
unsigned long data, *store, *postinc, disp, inc; unsigned long data, *store, *postinc, disp, inc, sp;
mm_segment_t seg; mm_segment_t seg;
siginfo_t info; siginfo_t info;
uint32_t opcode, noc, xo, xm; uint32_t opcode, noc, xo, xm;
...@@ -330,7 +331,12 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) ...@@ -330,7 +331,12 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
void *address; void *address;
unsigned tmp, npop, dispsz, loop; unsigned tmp, npop, dispsz, loop;
kdebug("==>misalignment({pc=%lx})", regs->pc); if (user_mode(regs))
sp = regs->sp;
else
sp = (unsigned long) regs + sizeof(*regs);
kdebug("==>misalignment({pc=%lx,sp=%lx})", regs->pc, sp);
if (regs->epsw & EPSW_IE) if (regs->epsw & EPSW_IE)
asm volatile("or %0,epsw" : : "i"(EPSW_IE)); asm volatile("or %0,epsw" : : "i"(EPSW_IE));
...@@ -496,7 +502,8 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) ...@@ -496,7 +502,8 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
if (pop->params[0] & 0x80000000) { if (pop->params[0] & 0x80000000) {
/* move memory to register */ /* move memory to register */
if (!misalignment_addr(registers, pop->params[0], opcode, disp, if (!misalignment_addr(registers, sp,
pop->params[0], opcode, disp,
&address, &postinc, &inc)) &address, &postinc, &inc))
goto bad_addr_mode; goto bad_addr_mode;
...@@ -520,7 +527,8 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) ...@@ -520,7 +527,8 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
&store)) &store))
goto bad_reg_mode; goto bad_reg_mode;
if (!misalignment_addr(registers, pop->params[1], opcode, disp, if (!misalignment_addr(registers, sp,
pop->params[1], opcode, disp,
&address, &postinc, &inc)) &address, &postinc, &inc))
goto bad_addr_mode; goto bad_addr_mode;
...@@ -548,8 +556,9 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) ...@@ -548,8 +556,9 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
/* /*
* determine the address that was being accessed * determine the address that was being accessed
*/ */
static int misalignment_addr(unsigned long *registers, unsigned params, static int misalignment_addr(unsigned long *registers, unsigned long sp,
unsigned opcode, unsigned long disp, unsigned params, unsigned opcode,
unsigned long disp,
void **_address, unsigned long **_postinc, void **_address, unsigned long **_postinc,
unsigned long *_inc) unsigned long *_inc)
{ {
...@@ -618,7 +627,7 @@ static int misalignment_addr(unsigned long *registers, unsigned params, ...@@ -618,7 +627,7 @@ static int misalignment_addr(unsigned long *registers, unsigned params,
address += *postinc; address += *postinc;
break; break;
case SP: case SP:
address += registers[REG_SP >> 2]; address += sp;
break; break;
/* displacements are either to be added to the address /* displacements are either to be added to the address
...@@ -642,6 +651,12 @@ static int misalignment_addr(unsigned long *registers, unsigned params, ...@@ -642,6 +651,12 @@ static int misalignment_addr(unsigned long *registers, unsigned params,
asm("asr 28,%0" : "=r"(tmp) : "0"(tmp)); asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
disp = (long) tmp; disp = (long) tmp;
goto displace_or_inc; goto displace_or_inc;
case IMM8:
disp &= 0x000000ff;
goto displace_or_inc;
case IMM16:
disp &= 0x0000ffff;
goto displace_or_inc;
case IMM24: case IMM24:
disp &= 0x00ffffff; disp &= 0x00ffffff;
goto displace_or_inc; goto displace_or_inc;
......
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