aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMagnus Damm <magnus.damm@gmail.com>2008-02-07 06:04:12 -0500
committerPaul Mundt <lethal@linux-sh.org>2008-02-14 00:22:09 -0500
commit4b5a9ef5279aed2c34d92fee62cf6d0c6ffacbaa (patch)
tree52dba448fd983fc6261e83e77a2b9addb7138917 /arch
parent4252c659a4e7f4260e4bdc87538578236c51ab2d (diff)
sh: use opcode_t and enable unaligned code for sh2a
This patch converts the unaligned access handling code to use opcode_t instead of u16. While at it, enable unaligned access handling for sh2a. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/sh/kernel/traps_32.c59
1 files changed, 25 insertions, 34 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 2e7dd2ebec9a..25b1b8672cf0 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -179,7 +179,7 @@ static inline void sign_extend(unsigned int count, unsigned char *dst)
179 * (if that instruction is in a branch delay slot) 179 * (if that instruction is in a branch delay slot)
180 * - return 0 if emulation okay, -EFAULT on existential error 180 * - return 0 if emulation okay, -EFAULT on existential error
181 */ 181 */
182static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) 182static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
183{ 183{
184 int ret, index, count; 184 int ret, index, count;
185 unsigned long *rm, *rn; 185 unsigned long *rm, *rn;
@@ -320,11 +320,13 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
320 * emulate the instruction in the delay slot 320 * emulate the instruction in the delay slot
321 * - fetches the instruction from PC+2 321 * - fetches the instruction from PC+2
322 */ 322 */
323static inline int handle_unaligned_delayslot(struct pt_regs *regs) 323static inline int handle_unaligned_delayslot(struct pt_regs *regs,
324 opcode_t old_instruction)
324{ 325{
325 u16 instruction; 326 opcode_t instruction;
327 void *addr = (void *)(regs->pc + instruction_size(old_instruction));
326 328
327 if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) { 329 if (copy_from_user(&instruction, addr, sizeof(instruction))) {
328 /* the instruction-fetch faulted */ 330 /* the instruction-fetch faulted */
329 if (user_mode(regs)) 331 if (user_mode(regs))
330 return -EFAULT; 332 return -EFAULT;
@@ -334,7 +336,7 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs)
334 regs, 0); 336 regs, 0);
335 } 337 }
336 338
337 return handle_unaligned_ins(instruction,regs); 339 return handle_unaligned_ins(instruction, regs);
338} 340}
339 341
340/* 342/*
@@ -357,10 +359,10 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs)
357 * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit 359 * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
358 * opcodes.. 360 * opcodes..
359 */ 361 */
360#ifndef CONFIG_CPU_SH2A 362
361static int handle_unaligned_notify_count = 10; 363static int handle_unaligned_notify_count = 10;
362 364
363static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) 365static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs)
364{ 366{
365 u_int rm; 367 u_int rm;
366 int ret, index; 368 int ret, index;
@@ -375,7 +377,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
375 printk(KERN_NOTICE "Fixing up unaligned userspace access " 377 printk(KERN_NOTICE "Fixing up unaligned userspace access "
376 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", 378 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
377 current->comm, task_pid_nr(current), 379 current->comm, task_pid_nr(current),
378 (u16 *)regs->pc, instruction); 380 (void *)regs->pc, instruction);
379 } 381 }
380 382
381 ret = -EFAULT; 383 ret = -EFAULT;
@@ -383,19 +385,19 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
383 case 0x0000: 385 case 0x0000:
384 if (instruction==0x000B) { 386 if (instruction==0x000B) {
385 /* rts */ 387 /* rts */
386 ret = handle_unaligned_delayslot(regs); 388 ret = handle_unaligned_delayslot(regs, instruction);
387 if (ret==0) 389 if (ret==0)
388 regs->pc = regs->pr; 390 regs->pc = regs->pr;
389 } 391 }
390 else if ((instruction&0x00FF)==0x0023) { 392 else if ((instruction&0x00FF)==0x0023) {
391 /* braf @Rm */ 393 /* braf @Rm */
392 ret = handle_unaligned_delayslot(regs); 394 ret = handle_unaligned_delayslot(regs, instruction);
393 if (ret==0) 395 if (ret==0)
394 regs->pc += rm + 4; 396 regs->pc += rm + 4;
395 } 397 }
396 else if ((instruction&0x00FF)==0x0003) { 398 else if ((instruction&0x00FF)==0x0003) {
397 /* bsrf @Rm */ 399 /* bsrf @Rm */
398 ret = handle_unaligned_delayslot(regs); 400 ret = handle_unaligned_delayslot(regs, instruction);
399 if (ret==0) { 401 if (ret==0) {
400 regs->pr = regs->pc + 4; 402 regs->pr = regs->pc + 4;
401 regs->pc += rm + 4; 403 regs->pc += rm + 4;
@@ -416,13 +418,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
416 case 0x4000: 418 case 0x4000:
417 if ((instruction&0x00FF)==0x002B) { 419 if ((instruction&0x00FF)==0x002B) {
418 /* jmp @Rm */ 420 /* jmp @Rm */
419 ret = handle_unaligned_delayslot(regs); 421 ret = handle_unaligned_delayslot(regs, instruction);
420 if (ret==0) 422 if (ret==0)
421 regs->pc = rm; 423 regs->pc = rm;
422 } 424 }
423 else if ((instruction&0x00FF)==0x000B) { 425 else if ((instruction&0x00FF)==0x000B) {
424 /* jsr @Rm */ 426 /* jsr @Rm */
425 ret = handle_unaligned_delayslot(regs); 427 ret = handle_unaligned_delayslot(regs, instruction);
426 if (ret==0) { 428 if (ret==0) {
427 regs->pr = regs->pc + 4; 429 regs->pr = regs->pc + 4;
428 regs->pc = rm; 430 regs->pc = rm;
@@ -449,7 +451,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
449 case 0x0B00: /* bf lab - no delayslot*/ 451 case 0x0B00: /* bf lab - no delayslot*/
450 break; 452 break;
451 case 0x0F00: /* bf/s lab */ 453 case 0x0F00: /* bf/s lab */
452 ret = handle_unaligned_delayslot(regs); 454 ret = handle_unaligned_delayslot(regs, instruction);
453 if (ret==0) { 455 if (ret==0) {
454#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) 456#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
455 if ((regs->sr & 0x00000001) != 0) 457 if ((regs->sr & 0x00000001) != 0)
@@ -462,7 +464,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
462 case 0x0900: /* bt lab - no delayslot */ 464 case 0x0900: /* bt lab - no delayslot */
463 break; 465 break;
464 case 0x0D00: /* bt/s lab */ 466 case 0x0D00: /* bt/s lab */
465 ret = handle_unaligned_delayslot(regs); 467 ret = handle_unaligned_delayslot(regs, instruction);
466 if (ret==0) { 468 if (ret==0) {
467#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) 469#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
468 if ((regs->sr & 0x00000001) == 0) 470 if ((regs->sr & 0x00000001) == 0)
@@ -476,13 +478,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
476 break; 478 break;
477 479
478 case 0xA000: /* bra label */ 480 case 0xA000: /* bra label */
479 ret = handle_unaligned_delayslot(regs); 481 ret = handle_unaligned_delayslot(regs, instruction);
480 if (ret==0) 482 if (ret==0)
481 regs->pc += SH_PC_12BIT_OFFSET(instruction); 483 regs->pc += SH_PC_12BIT_OFFSET(instruction);
482 break; 484 break;
483 485
484 case 0xB000: /* bsr label */ 486 case 0xB000: /* bsr label */
485 ret = handle_unaligned_delayslot(regs); 487 ret = handle_unaligned_delayslot(regs, instruction);
486 if (ret==0) { 488 if (ret==0) {
487 regs->pr = regs->pc + 4; 489 regs->pr = regs->pc + 4;
488 regs->pc += SH_PC_12BIT_OFFSET(instruction); 490 regs->pc += SH_PC_12BIT_OFFSET(instruction);
@@ -493,12 +495,11 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
493 495
494 /* handle non-delay-slot instruction */ 496 /* handle non-delay-slot instruction */
495 simple: 497 simple:
496 ret = handle_unaligned_ins(instruction,regs); 498 ret = handle_unaligned_ins(instruction, regs);
497 if (ret==0) 499 if (ret==0)
498 regs->pc += instruction_size(instruction); 500 regs->pc += instruction_size(instruction);
499 return ret; 501 return ret;
500} 502}
501#endif /* CONFIG_CPU_SH2A */
502 503
503#ifdef CONFIG_CPU_HAS_SR_RB 504#ifdef CONFIG_CPU_HAS_SR_RB
504#define lookup_exception_vector(x) \ 505#define lookup_exception_vector(x) \
@@ -526,10 +527,8 @@ asmlinkage void do_address_error(struct pt_regs *regs,
526 unsigned long error_code = 0; 527 unsigned long error_code = 0;
527 mm_segment_t oldfs; 528 mm_segment_t oldfs;
528 siginfo_t info; 529 siginfo_t info;
529#ifndef CONFIG_CPU_SH2A 530 opcode_t instruction;
530 u16 instruction;
531 int tmp; 531 int tmp;
532#endif
533 532
534 /* Intentional ifdef */ 533 /* Intentional ifdef */
535#ifdef CONFIG_CPU_HAS_SR_RB 534#ifdef CONFIG_CPU_HAS_SR_RB
@@ -549,9 +548,9 @@ asmlinkage void do_address_error(struct pt_regs *regs,
549 goto uspace_segv; 548 goto uspace_segv;
550 } 549 }
551 550
552#ifndef CONFIG_CPU_SH2A
553 set_fs(USER_DS); 551 set_fs(USER_DS);
554 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { 552 if (copy_from_user(&instruction, (void *)(regs->pc),
553 sizeof(instruction))) {
555 /* Argh. Fault on the instruction itself. 554 /* Argh. Fault on the instruction itself.
556 This should never happen non-SMP 555 This should never happen non-SMP
557 */ 556 */
@@ -564,8 +563,6 @@ asmlinkage void do_address_error(struct pt_regs *regs,
564 563
565 if (tmp==0) 564 if (tmp==0)
566 return; /* sorted */ 565 return; /* sorted */
567#endif
568
569uspace_segv: 566uspace_segv:
570 printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " 567 printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
571 "access (PC %lx PR %lx)\n", current->comm, regs->pc, 568 "access (PC %lx PR %lx)\n", current->comm, regs->pc,
@@ -580,9 +577,9 @@ uspace_segv:
580 if (regs->pc & 1) 577 if (regs->pc & 1)
581 die("unaligned program counter", regs, error_code); 578 die("unaligned program counter", regs, error_code);
582 579
583#ifndef CONFIG_CPU_SH2A
584 set_fs(KERNEL_DS); 580 set_fs(KERNEL_DS);
585 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { 581 if (copy_from_user(&instruction, (void *)(regs->pc),
582 sizeof(instruction))) {
586 /* Argh. Fault on the instruction itself. 583 /* Argh. Fault on the instruction itself.
587 This should never happen non-SMP 584 This should never happen non-SMP
588 */ 585 */
@@ -592,12 +589,6 @@ uspace_segv:
592 589
593 handle_unaligned_access(instruction, regs); 590 handle_unaligned_access(instruction, regs);
594 set_fs(oldfs); 591 set_fs(oldfs);
595#else
596 printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
597 "access\n", current->comm);
598
599 force_sig(SIGSEGV, current);
600#endif
601 } 592 }
602} 593}
603 594