aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/mm/misalignment.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-12 10:35:45 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-11-12 13:41:18 -0500
commitd3bd462865421dd8be310fac2d2f6da6069f9679 (patch)
tree3b32df394ef7b5daec8360e86542be4248397abf /arch/mn10300/mm/misalignment.c
parent852c15b7362cf34e0d7949abefbfeeb0845d93b4 (diff)
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: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/mn10300/mm/misalignment.c')
-rw-r--r--arch/mn10300/mm/misalignment.c33
1 files changed, 24 insertions, 9 deletions
diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
index a59836804bc6..e247a6e1b8de 100644
--- a/arch/mn10300/mm/misalignment.c
+++ b/arch/mn10300/mm/misalignment.c
@@ -42,8 +42,9 @@
42#define kdebug(FMT, ...) do {} while (0) 42#define kdebug(FMT, ...) do {} while (0)
43#endif 43#endif
44 44
45static int misalignment_addr(unsigned long *registers, unsigned params, 45static int misalignment_addr(unsigned long *registers, unsigned long sp,
46 unsigned opcode, unsigned long disp, 46 unsigned params, unsigned opcode,
47 unsigned long disp,
47 void **_address, unsigned long **_postinc, 48 void **_address, unsigned long **_postinc,
48 unsigned long *_inc); 49 unsigned long *_inc);
49 50
@@ -322,7 +323,7 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
322 const struct exception_table_entry *fixup; 323 const struct exception_table_entry *fixup;
323 const struct mn10300_opcode *pop; 324 const struct mn10300_opcode *pop;
324 unsigned long *registers = (unsigned long *) regs; 325 unsigned long *registers = (unsigned long *) regs;
325 unsigned long data, *store, *postinc, disp, inc; 326 unsigned long data, *store, *postinc, disp, inc, sp;
326 mm_segment_t seg; 327 mm_segment_t seg;
327 siginfo_t info; 328 siginfo_t info;
328 uint32_t opcode, noc, xo, xm; 329 uint32_t opcode, noc, xo, xm;
@@ -330,7 +331,12 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
330 void *address; 331 void *address;
331 unsigned tmp, npop, dispsz, loop; 332 unsigned tmp, npop, dispsz, loop;
332 333
333 kdebug("==>misalignment({pc=%lx})", regs->pc); 334 if (user_mode(regs))
335 sp = regs->sp;
336 else
337 sp = (unsigned long) regs + sizeof(*regs);
338
339 kdebug("==>misalignment({pc=%lx,sp=%lx})", regs->pc, sp);
334 340
335 if (regs->epsw & EPSW_IE) 341 if (regs->epsw & EPSW_IE)
336 asm volatile("or %0,epsw" : : "i"(EPSW_IE)); 342 asm volatile("or %0,epsw" : : "i"(EPSW_IE));
@@ -496,7 +502,8 @@ found_opcode:
496 502
497 if (pop->params[0] & 0x80000000) { 503 if (pop->params[0] & 0x80000000) {
498 /* move memory to register */ 504 /* move memory to register */
499 if (!misalignment_addr(registers, pop->params[0], opcode, disp, 505 if (!misalignment_addr(registers, sp,
506 pop->params[0], opcode, disp,
500 &address, &postinc, &inc)) 507 &address, &postinc, &inc))
501 goto bad_addr_mode; 508 goto bad_addr_mode;
502 509
@@ -520,7 +527,8 @@ found_opcode:
520 &store)) 527 &store))
521 goto bad_reg_mode; 528 goto bad_reg_mode;
522 529
523 if (!misalignment_addr(registers, pop->params[1], opcode, disp, 530 if (!misalignment_addr(registers, sp,
531 pop->params[1], opcode, disp,
524 &address, &postinc, &inc)) 532 &address, &postinc, &inc))
525 goto bad_addr_mode; 533 goto bad_addr_mode;
526 534
@@ -548,8 +556,9 @@ found_opcode:
548/* 556/*
549 * determine the address that was being accessed 557 * determine the address that was being accessed
550 */ 558 */
551static int misalignment_addr(unsigned long *registers, unsigned params, 559static int misalignment_addr(unsigned long *registers, unsigned long sp,
552 unsigned opcode, unsigned long disp, 560 unsigned params, unsigned opcode,
561 unsigned long disp,
553 void **_address, unsigned long **_postinc, 562 void **_address, unsigned long **_postinc,
554 unsigned long *_inc) 563 unsigned long *_inc)
555{ 564{
@@ -618,7 +627,7 @@ static int misalignment_addr(unsigned long *registers, unsigned params,
618 address += *postinc; 627 address += *postinc;
619 break; 628 break;
620 case SP: 629 case SP:
621 address += registers[REG_SP >> 2]; 630 address += sp;
622 break; 631 break;
623 632
624 /* displacements are either to be added to the address 633 /* displacements are either to be added to the address
@@ -642,6 +651,12 @@ static int misalignment_addr(unsigned long *registers, unsigned params,
642 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp)); 651 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
643 disp = (long) tmp; 652 disp = (long) tmp;
644 goto displace_or_inc; 653 goto displace_or_inc;
654 case IMM8:
655 disp &= 0x000000ff;
656 goto displace_or_inc;
657 case IMM16:
658 disp &= 0x0000ffff;
659 goto displace_or_inc;
645 case IMM24: 660 case IMM24:
646 disp &= 0x00ffffff; 661 disp &= 0x00ffffff;
647 goto displace_or_inc; 662 goto displace_or_inc;