diff options
author | David Howells <dhowells@redhat.com> | 2008-11-12 10:35:45 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-11-12 13:41:18 -0500 |
commit | d3bd462865421dd8be310fac2d2f6da6069f9679 (patch) | |
tree | 3b32df394ef7b5daec8360e86542be4248397abf /arch/mn10300 | |
parent | 852c15b7362cf34e0d7949abefbfeeb0845d93b4 (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')
-rw-r--r-- | arch/mn10300/mm/misalignment.c | 33 |
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 | ||
45 | static int misalignment_addr(unsigned long *registers, unsigned params, | 45 | static 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 | */ |
551 | static int misalignment_addr(unsigned long *registers, unsigned params, | 559 | static 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; |