MN10300: Handle misaligned postinc-with-imm addressing mode correctly

Correctly handle misalignment in MOV instructions with postinc-with-immediate
addressing mode operands. In these, the immediate value is the increment to
be applied the address register, not the displacement to the address.

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 6d615c78 ddb6d05c

+56 -51
+56 -51
arch/mn10300/mm/misalignment.c
··· 44 45 static int misalignment_addr(unsigned long *registers, unsigned params, 46 unsigned opcode, unsigned long disp, 47 - void **_address, unsigned long **_postinc); 48 49 static int misalignment_reg(unsigned long *registers, unsigned params, 50 unsigned opcode, unsigned long disp, ··· 151 }; 152 153 struct mn10300_opcode { 154 - const char *name; 155 u_int32_t opcode; 156 u_int32_t opmask; 157 unsigned exclusion; ··· 311 { "mov_lne", 0xf7e00009, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 312 { "mov_lra", 0xf7e0000a, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 313 314 - { 0, 0, 0, 0, 0, 0, {0}}, 315 }; 316 317 /* ··· 322 const struct exception_table_entry *fixup; 323 const struct mn10300_opcode *pop; 324 unsigned long *registers = (unsigned long *) regs; 325 - unsigned long data, *store, *postinc, disp; 326 mm_segment_t seg; 327 siginfo_t info; 328 uint32_t opcode, noc, xo, xm; 329 - uint8_t *pc, byte; 330 void *address; 331 unsigned tmp, npop, dispsz, loop; 332 ··· 348 opcode = byte; 349 noc = 8; 350 351 - for (pop = mn10300_opcodes; pop->name; pop++) { 352 npop = ilog2(pop->opcode | pop->opmask); 353 if (npop <= 0 || npop > 31) 354 continue; ··· 485 goto failed; 486 } 487 488 if (pop->params[0] & 0x80000000) { 489 /* move memory to register */ 490 if (!misalignment_addr(registers, pop->params[0], opcode, disp, 491 - &address, &postinc)) 492 goto bad_addr_mode; 493 494 if (!misalignment_reg(registers, pop->params[1], opcode, disp, 495 &store)) 496 goto bad_reg_mode; 497 498 - if (strcmp(pop->name, "mov") == 0 || 499 - memcmp(pop->name, "mov_l", 5) == 0) { 500 - kdebug("mov (%p),DARn", address); 501 - if (copy_from_user(&data, (void *) address, 4) != 0) 502 - goto transfer_failed; 503 - if (pop->params[0] & 0x1000000) 504 - *postinc += 4; 505 - } else if (strcmp(pop->name, "movhu") == 0) { 506 - kdebug("movhu (%p),DARn", address); 507 - data = 0; 508 - if (copy_from_user(&data, (void *) address, 2) != 0) 509 - goto transfer_failed; 510 - if (pop->params[0] & 0x1000000) 511 - *postinc += 2; 512 - } else { 513 - goto unsupported_instruction; 514 } 515 516 *store = data; ··· 521 goto bad_reg_mode; 522 523 if (!misalignment_addr(registers, pop->params[1], opcode, disp, 524 - &address, &postinc)) 525 goto bad_addr_mode; 526 527 data = *store; 528 529 - if (strcmp(pop->name, "mov") == 0) { 530 - kdebug("mov %lx,(%p)", data, address); 531 - if (copy_to_user((void *) address, &data, 4) != 0) 532 - goto transfer_failed; 533 - if (pop->params[1] & 0x1000000) 534 - *postinc += 4; 535 - } else if (strcmp(pop->name, "movhu") == 0) { 536 - kdebug("movhu %hx,(%p)", (uint16_t) data, address); 537 - if (copy_to_user((void *) address, &data, 2) != 0) 538 - goto transfer_failed; 539 - if (pop->params[1] & 0x1000000) 540 - *postinc += 2; 541 - } else { 542 - goto unsupported_instruction; 543 - } 544 } 545 546 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz; ··· 550 */ 551 static int misalignment_addr(unsigned long *registers, unsigned params, 552 unsigned opcode, unsigned long disp, 553 - void **_address, unsigned long **_postinc) 554 { 555 unsigned long *postinc = NULL, address = 0, tmp; 556 557 params &= 0x00ffffff; 558 ··· 621 address += registers[REG_SP >> 2]; 622 break; 623 624 case SD8: 625 case SIMM8: 626 - address += (int32_t) (int8_t) (disp & 0xff); 627 - break; 628 case SD16: 629 - address += (int32_t) (int16_t) (disp & 0xffff); 630 - break; 631 case SD24: 632 tmp = disp << 8; 633 asm("asr 8,%0" : "=r"(tmp) : "0"(tmp)); 634 - address += tmp; 635 - break; 636 case SIMM4_2: 637 tmp = opcode >> 4 & 0x0f; 638 tmp <<= 28; 639 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp)); 640 - address += tmp; 641 - break; 642 case IMM24: 643 - address += disp & 0x00ffffff; 644 - break; 645 case IMM32: 646 case IMM32_MEM: 647 case IMM32_HIGH8: 648 case IMM32_HIGH8_MEM: 649 - address += disp; 650 break; 651 default: 652 BUG();
··· 44 45 static int misalignment_addr(unsigned long *registers, unsigned params, 46 unsigned opcode, unsigned long disp, 47 + void **_address, unsigned long **_postinc, 48 + unsigned long *_inc); 49 50 static int misalignment_reg(unsigned long *registers, unsigned params, 51 unsigned opcode, unsigned long disp, ··· 150 }; 151 152 struct mn10300_opcode { 153 + const char name[8]; 154 u_int32_t opcode; 155 u_int32_t opmask; 156 unsigned exclusion; ··· 310 { "mov_lne", 0xf7e00009, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 311 { "mov_lra", 0xf7e0000a, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 312 313 + { "", 0, 0, 0, 0, 0, {0}}, 314 }; 315 316 /* ··· 321 const struct exception_table_entry *fixup; 322 const struct mn10300_opcode *pop; 323 unsigned long *registers = (unsigned long *) regs; 324 + unsigned long data, *store, *postinc, disp, inc; 325 mm_segment_t seg; 326 siginfo_t info; 327 uint32_t opcode, noc, xo, xm; 328 + uint8_t *pc, byte, datasz; 329 void *address; 330 unsigned tmp, npop, dispsz, loop; 331 ··· 347 opcode = byte; 348 noc = 8; 349 350 + for (pop = mn10300_opcodes; pop->name[0]; pop++) { 351 npop = ilog2(pop->opcode | pop->opmask); 352 if (npop <= 0 || npop > 31) 353 continue; ··· 484 goto failed; 485 } 486 487 + /* determine the data transfer size of the move */ 488 + if (pop->name[3] == 0 || /* "mov" */ 489 + pop->name[4] == 'l') /* mov_lcc */ 490 + inc = datasz = 4; 491 + else if (pop->name[3] == 'h') /* movhu */ 492 + inc = datasz = 2; 493 + else 494 + goto unsupported_instruction; 495 + 496 if (pop->params[0] & 0x80000000) { 497 /* move memory to register */ 498 if (!misalignment_addr(registers, pop->params[0], opcode, disp, 499 + &address, &postinc, &inc)) 500 goto bad_addr_mode; 501 502 if (!misalignment_reg(registers, pop->params[1], opcode, disp, 503 &store)) 504 goto bad_reg_mode; 505 506 + kdebug("mov%u (%p),DARn", datasz, address); 507 + if (copy_from_user(&data, (void *) address, datasz) != 0) 508 + goto transfer_failed; 509 + if (pop->params[0] & 0x1000000) { 510 + kdebug("inc=%lx", inc); 511 + *postinc += inc; 512 } 513 514 *store = data; ··· 521 goto bad_reg_mode; 522 523 if (!misalignment_addr(registers, pop->params[1], opcode, disp, 524 + &address, &postinc, &inc)) 525 goto bad_addr_mode; 526 527 data = *store; 528 529 + kdebug("mov%u %lx,(%p)", datasz, data, address); 530 + if (copy_to_user((void *) address, &data, datasz) != 0) 531 + goto transfer_failed; 532 + if (pop->params[1] & 0x1000000) 533 + *postinc += inc; 534 } 535 536 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz; ··· 560 */ 561 static int misalignment_addr(unsigned long *registers, unsigned params, 562 unsigned opcode, unsigned long disp, 563 + void **_address, unsigned long **_postinc, 564 + unsigned long *_inc) 565 { 566 unsigned long *postinc = NULL, address = 0, tmp; 567 + 568 + if (!(params & 0x1000000)) { 569 + kdebug("noinc"); 570 + *_inc = 0; 571 + _inc = NULL; 572 + } 573 574 params &= 0x00ffffff; 575 ··· 624 address += registers[REG_SP >> 2]; 625 break; 626 627 + /* displacements are either to be added to the address 628 + * before use, or, in the case of post-inc addressing, 629 + * to be added into the base register after use */ 630 case SD8: 631 case SIMM8: 632 + disp = (long) (int8_t) (disp & 0xff); 633 + goto displace_or_inc; 634 case SD16: 635 + disp = (long) (int16_t) (disp & 0xffff); 636 + goto displace_or_inc; 637 case SD24: 638 tmp = disp << 8; 639 asm("asr 8,%0" : "=r"(tmp) : "0"(tmp)); 640 + disp = (long) tmp; 641 + goto displace_or_inc; 642 case SIMM4_2: 643 tmp = opcode >> 4 & 0x0f; 644 tmp <<= 28; 645 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp)); 646 + disp = (long) tmp; 647 + goto displace_or_inc; 648 case IMM24: 649 + disp &= 0x00ffffff; 650 + goto displace_or_inc; 651 case IMM32: 652 case IMM32_MEM: 653 case IMM32_HIGH8: 654 case IMM32_HIGH8_MEM: 655 + displace_or_inc: 656 + kdebug("%s %lx", _inc ? "incr" : "disp", disp); 657 + if (!_inc) 658 + address += disp; 659 + else 660 + *_inc = disp; 661 break; 662 default: 663 BUG();