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>

authored by David Howells and committed by Linus Torvalds d3bd4628 852c15b7

+24 -9
+24 -9
arch/mn10300/mm/misalignment.c
··· 42 42 #define kdebug(FMT, ...) do {} while (0) 43 43 #endif 44 44 45 - static int misalignment_addr(unsigned long *registers, unsigned params, 46 - unsigned opcode, unsigned long disp, 45 + static int misalignment_addr(unsigned long *registers, unsigned long sp, 46 + unsigned params, unsigned opcode, 47 + unsigned long disp, 47 48 void **_address, unsigned long **_postinc, 48 49 unsigned long *_inc); 49 50 ··· 323 322 const struct exception_table_entry *fixup; 324 323 const struct mn10300_opcode *pop; 325 324 unsigned long *registers = (unsigned long *) regs; 326 - unsigned long data, *store, *postinc, disp, inc; 325 + unsigned long data, *store, *postinc, disp, inc, sp; 327 326 mm_segment_t seg; 328 327 siginfo_t info; 329 328 uint32_t opcode, noc, xo, xm; ··· 331 330 void *address; 332 331 unsigned tmp, npop, dispsz, loop; 333 332 334 - kdebug("==>misalignment({pc=%lx})", regs->pc); 333 + if (user_mode(regs)) 334 + sp = regs->sp; 335 + else 336 + sp = (unsigned long) regs + sizeof(*regs); 337 + 338 + kdebug("==>misalignment({pc=%lx,sp=%lx})", regs->pc, sp); 335 339 336 340 if (regs->epsw & EPSW_IE) 337 341 asm volatile("or %0,epsw" : : "i"(EPSW_IE)); ··· 502 496 503 497 if (pop->params[0] & 0x80000000) { 504 498 /* move memory to register */ 505 - if (!misalignment_addr(registers, pop->params[0], opcode, disp, 499 + if (!misalignment_addr(registers, sp, 500 + pop->params[0], opcode, disp, 506 501 &address, &postinc, &inc)) 507 502 goto bad_addr_mode; 508 503 ··· 527 520 &store)) 528 521 goto bad_reg_mode; 529 522 530 - if (!misalignment_addr(registers, pop->params[1], opcode, disp, 523 + if (!misalignment_addr(registers, sp, 524 + pop->params[1], opcode, disp, 531 525 &address, &postinc, &inc)) 532 526 goto bad_addr_mode; 533 527 ··· 556 548 /* 557 549 * determine the address that was being accessed 558 550 */ 559 - static int misalignment_addr(unsigned long *registers, unsigned params, 560 - unsigned opcode, unsigned long disp, 551 + static int misalignment_addr(unsigned long *registers, unsigned long sp, 552 + unsigned params, unsigned opcode, 553 + unsigned long disp, 561 554 void **_address, unsigned long **_postinc, 562 555 unsigned long *_inc) 563 556 { ··· 627 618 address += *postinc; 628 619 break; 629 620 case SP: 630 - address += registers[REG_SP >> 2]; 621 + address += sp; 631 622 break; 632 623 633 624 /* displacements are either to be added to the address ··· 650 641 tmp <<= 28; 651 642 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp)); 652 643 disp = (long) tmp; 644 + goto displace_or_inc; 645 + case IMM8: 646 + disp &= 0x000000ff; 647 + goto displace_or_inc; 648 + case IMM16: 649 + disp &= 0x0000ffff; 653 650 goto displace_or_inc; 654 651 case IMM24: 655 652 disp &= 0x00ffffff;