diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-08-04 04:14:39 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-08-04 04:14:39 -0400 |
commit | c7914834ef3b8a396b7e82ea34ac07cdcfe6f868 (patch) | |
tree | 59f6f76dfca96cd7ad330ae3c281cfa57e98f44e /arch/sh/kernel | |
parent | c0fe478dbb14fd32e71d1383dbe302b54ce94134 (diff) |
sh: Tidy up NEFF-based sign extension for SH-5.
This consolidates all of the NEFF-based sign extension for SH-5.
In the future the other SH code will need to make use of this as well,
so make it generic in preparation for more 32/64 consolidation.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/process_64.c | 24 | ||||
-rw-r--r-- | arch/sh/kernel/signal_64.c | 38 |
2 files changed, 23 insertions, 39 deletions
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 24de74214940..1192398ef582 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c | |||
@@ -425,7 +425,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
425 | struct task_struct *p, struct pt_regs *regs) | 425 | struct task_struct *p, struct pt_regs *regs) |
426 | { | 426 | { |
427 | struct pt_regs *childregs; | 427 | struct pt_regs *childregs; |
428 | unsigned long long se; /* Sign extension */ | ||
429 | 428 | ||
430 | #ifdef CONFIG_SH_FPU | 429 | #ifdef CONFIG_SH_FPU |
431 | if(last_task_used_math == current) { | 430 | if(last_task_used_math == current) { |
@@ -441,11 +440,19 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
441 | 440 | ||
442 | *childregs = *regs; | 441 | *childregs = *regs; |
443 | 442 | ||
443 | /* | ||
444 | * Sign extend the edited stack. | ||
445 | * Note that thread.pc and thread.pc will stay | ||
446 | * 32-bit wide and context switch must take care | ||
447 | * of NEFF sign extension. | ||
448 | */ | ||
444 | if (user_mode(regs)) { | 449 | if (user_mode(regs)) { |
445 | childregs->regs[15] = usp; | 450 | childregs->regs[15] = neff_sign_extend(usp); |
446 | p->thread.uregs = childregs; | 451 | p->thread.uregs = childregs; |
447 | } else { | 452 | } else { |
448 | childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE; | 453 | childregs->regs[15] = |
454 | neff_sign_extend((unsigned long)task_stack_page(p) + | ||
455 | THREAD_SIZE); | ||
449 | } | 456 | } |
450 | 457 | ||
451 | childregs->regs[9] = 0; /* Set return value for child */ | 458 | childregs->regs[9] = 0; /* Set return value for child */ |
@@ -454,17 +461,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
454 | p->thread.sp = (unsigned long) childregs; | 461 | p->thread.sp = (unsigned long) childregs; |
455 | p->thread.pc = (unsigned long) ret_from_fork; | 462 | p->thread.pc = (unsigned long) ret_from_fork; |
456 | 463 | ||
457 | /* | ||
458 | * Sign extend the edited stack. | ||
459 | * Note that thread.pc and thread.pc will stay | ||
460 | * 32-bit wide and context switch must take care | ||
461 | * of NEFF sign extension. | ||
462 | */ | ||
463 | |||
464 | se = childregs->regs[15]; | ||
465 | se = (se & NEFF_SIGN) ? (se | NEFF_MASK) : se; | ||
466 | childregs->regs[15] = se; | ||
467 | |||
468 | return 0; | 464 | return 0; |
469 | } | 465 | } |
470 | 466 | ||
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 0663a0ee6021..026fd1cfe17d 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
@@ -561,13 +561,11 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
561 | /* Set up to return from userspace. If provided, use a stub | 561 | /* Set up to return from userspace. If provided, use a stub |
562 | already in userspace. */ | 562 | already in userspace. */ |
563 | if (ka->sa.sa_flags & SA_RESTORER) { | 563 | if (ka->sa.sa_flags & SA_RESTORER) { |
564 | DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; | ||
565 | |||
566 | /* | 564 | /* |
567 | * On SH5 all edited pointers are subject to NEFF | 565 | * On SH5 all edited pointers are subject to NEFF |
568 | */ | 566 | */ |
569 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? | 567 | DEREF_REG_PR = neff_sign_extend((unsigned long) |
570 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; | 568 | ka->sa.sa_restorer | 0x1); |
571 | } else { | 569 | } else { |
572 | /* | 570 | /* |
573 | * Different approach on SH5. | 571 | * Different approach on SH5. |
@@ -580,9 +578,8 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
580 | * . being code, linker turns ShMedia bit on, always | 578 | * . being code, linker turns ShMedia bit on, always |
581 | * dereference index -1. | 579 | * dereference index -1. |
582 | */ | 580 | */ |
583 | DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; | 581 | DEREF_REG_PR = neff_sign_extend((unsigned long) |
584 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? | 582 | frame->retcode | 0x01); |
585 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; | ||
586 | 583 | ||
587 | if (__copy_to_user(frame->retcode, | 584 | if (__copy_to_user(frame->retcode, |
588 | (void *)((unsigned long)sa_default_restorer & (~1)), 16) != 0) | 585 | (void *)((unsigned long)sa_default_restorer & (~1)), 16) != 0) |
@@ -596,9 +593,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
596 | * Set up registers for signal handler. | 593 | * Set up registers for signal handler. |
597 | * All edited pointers are subject to NEFF. | 594 | * All edited pointers are subject to NEFF. |
598 | */ | 595 | */ |
599 | regs->regs[REG_SP] = (unsigned long) frame; | 596 | regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame); |
600 | regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? | ||
601 | (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; | ||
602 | regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ | 597 | regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ |
603 | 598 | ||
604 | /* FIXME: | 599 | /* FIXME: |
@@ -613,8 +608,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
613 | regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc; | 608 | regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc; |
614 | regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc; | 609 | regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc; |
615 | 610 | ||
616 | regs->pc = (unsigned long) ka->sa.sa_handler; | 611 | regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler); |
617 | regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; | ||
618 | 612 | ||
619 | set_fs(USER_DS); | 613 | set_fs(USER_DS); |
620 | 614 | ||
@@ -676,13 +670,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
676 | /* Set up to return from userspace. If provided, use a stub | 670 | /* Set up to return from userspace. If provided, use a stub |
677 | already in userspace. */ | 671 | already in userspace. */ |
678 | if (ka->sa.sa_flags & SA_RESTORER) { | 672 | if (ka->sa.sa_flags & SA_RESTORER) { |
679 | DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; | ||
680 | |||
681 | /* | 673 | /* |
682 | * On SH5 all edited pointers are subject to NEFF | 674 | * On SH5 all edited pointers are subject to NEFF |
683 | */ | 675 | */ |
684 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? | 676 | DEREF_REG_PR = neff_sign_extend((unsigned long) |
685 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; | 677 | ka->sa.sa_restorer | 0x1); |
686 | } else { | 678 | } else { |
687 | /* | 679 | /* |
688 | * Different approach on SH5. | 680 | * Different approach on SH5. |
@@ -695,15 +687,14 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
695 | * . being code, linker turns ShMedia bit on, always | 687 | * . being code, linker turns ShMedia bit on, always |
696 | * dereference index -1. | 688 | * dereference index -1. |
697 | */ | 689 | */ |
698 | 690 | DEREF_REG_PR = neff_sign_extend((unsigned long) | |
699 | DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; | 691 | frame->retcode | 0x01); |
700 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? | ||
701 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; | ||
702 | 692 | ||
703 | if (__copy_to_user(frame->retcode, | 693 | if (__copy_to_user(frame->retcode, |
704 | (void *)((unsigned long)sa_default_rt_restorer & (~1)), 16) != 0) | 694 | (void *)((unsigned long)sa_default_rt_restorer & (~1)), 16) != 0) |
705 | goto give_sigsegv; | 695 | goto give_sigsegv; |
706 | 696 | ||
697 | /* Cohere the trampoline with the I-cache. */ | ||
707 | flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15); | 698 | flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15); |
708 | } | 699 | } |
709 | 700 | ||
@@ -711,14 +702,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
711 | * Set up registers for signal handler. | 702 | * Set up registers for signal handler. |
712 | * All edited pointers are subject to NEFF. | 703 | * All edited pointers are subject to NEFF. |
713 | */ | 704 | */ |
714 | regs->regs[REG_SP] = (unsigned long) frame; | 705 | regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame); |
715 | regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? | ||
716 | (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; | ||
717 | regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ | 706 | regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ |
718 | regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info; | 707 | regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info; |
719 | regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext; | 708 | regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext; |
720 | regs->pc = (unsigned long) ka->sa.sa_handler; | 709 | regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler); |
721 | regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; | ||
722 | 710 | ||
723 | set_fs(USER_DS); | 711 | set_fs(USER_DS); |
724 | 712 | ||