Commit b6d3abda6892e9ce4aa08bd9f5d83fee29efec71
1 parent
cbdbb771
First try at supporting ordinary signals for CRIS linux-user guests.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3999 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
175 additions
and
0 deletions
linux-user/main.c
| @@ -1673,6 +1673,9 @@ void cpu_loop (CPUState *env) | @@ -1673,6 +1673,9 @@ void cpu_loop (CPUState *env) | ||
| 1673 | queue_signal(info.si_signo, &info); | 1673 | queue_signal(info.si_signo, &info); |
| 1674 | } | 1674 | } |
| 1675 | break; | 1675 | break; |
| 1676 | + case EXCP_INTERRUPT: | ||
| 1677 | + /* just indicate that signals should be handled asap */ | ||
| 1678 | + break; | ||
| 1676 | case EXCP_BREAK: | 1679 | case EXCP_BREAK: |
| 1677 | ret = do_syscall(env, | 1680 | ret = do_syscall(env, |
| 1678 | env->regs[9], | 1681 | env->regs[9], |
linux-user/signal.c
| @@ -2706,6 +2706,178 @@ badframe: | @@ -2706,6 +2706,178 @@ badframe: | ||
| 2706 | force_sig(TARGET_SIGSEGV); | 2706 | force_sig(TARGET_SIGSEGV); |
| 2707 | return 0; | 2707 | return 0; |
| 2708 | } | 2708 | } |
| 2709 | +#elif defined(TARGET_CRIS) | ||
| 2710 | + | ||
| 2711 | +struct target_sigcontext { | ||
| 2712 | + struct target_pt_regs regs; /* needs to be first */ | ||
| 2713 | + uint32_t oldmask; | ||
| 2714 | + uint32_t usp; /* usp before stacking this gunk on it */ | ||
| 2715 | +}; | ||
| 2716 | + | ||
| 2717 | +/* Signal frames. */ | ||
| 2718 | +struct target_signal_frame { | ||
| 2719 | + struct target_sigcontext sc; | ||
| 2720 | + uint32_t extramask[TARGET_NSIG_WORDS - 1]; | ||
| 2721 | + uint8_t retcode[8]; /* Trampoline code. */ | ||
| 2722 | +}; | ||
| 2723 | + | ||
| 2724 | +struct rt_signal_frame { | ||
| 2725 | + struct siginfo *pinfo; | ||
| 2726 | + void *puc; | ||
| 2727 | + struct siginfo info; | ||
| 2728 | + struct ucontext uc; | ||
| 2729 | + uint8_t retcode[8]; /* Trampoline code. */ | ||
| 2730 | +}; | ||
| 2731 | + | ||
| 2732 | +static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env) | ||
| 2733 | +{ | ||
| 2734 | + sc->regs.r0 = env->regs[0]; | ||
| 2735 | + sc->regs.r1 = env->regs[1]; | ||
| 2736 | + sc->regs.r2 = env->regs[2]; | ||
| 2737 | + sc->regs.r3 = env->regs[3]; | ||
| 2738 | + sc->regs.r4 = env->regs[4]; | ||
| 2739 | + sc->regs.r5 = env->regs[5]; | ||
| 2740 | + sc->regs.r6 = env->regs[6]; | ||
| 2741 | + sc->regs.r7 = env->regs[7]; | ||
| 2742 | + sc->regs.r8 = env->regs[8]; | ||
| 2743 | + sc->regs.r9 = env->regs[9]; | ||
| 2744 | + sc->regs.r10 = env->regs[10]; | ||
| 2745 | + sc->regs.r11 = env->regs[11]; | ||
| 2746 | + sc->regs.r12 = env->regs[12]; | ||
| 2747 | + sc->regs.r13 = env->regs[13]; | ||
| 2748 | + sc->usp = env->regs[14]; | ||
| 2749 | + sc->regs.acr = env->regs[15]; | ||
| 2750 | + sc->regs.srp = env->pregs[PR_SRP]; | ||
| 2751 | + sc->regs.erp = env->pc; | ||
| 2752 | + | ||
| 2753 | + env->pregs[PR_ERP] = env->pc; | ||
| 2754 | +} | ||
| 2755 | +static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env) | ||
| 2756 | +{ | ||
| 2757 | + env->regs[0] = sc->regs.r0; | ||
| 2758 | + env->regs[1] = sc->regs.r1; | ||
| 2759 | + env->regs[2] = sc->regs.r2; | ||
| 2760 | + env->regs[3] = sc->regs.r3; | ||
| 2761 | + env->regs[4] = sc->regs.r4; | ||
| 2762 | + env->regs[5] = sc->regs.r5; | ||
| 2763 | + env->regs[6] = sc->regs.r6; | ||
| 2764 | + env->regs[7] = sc->regs.r7; | ||
| 2765 | + env->regs[8] = sc->regs.r8; | ||
| 2766 | + env->regs[9] = sc->regs.r9; | ||
| 2767 | + env->regs[10] = sc->regs.r10; | ||
| 2768 | + env->regs[11] = sc->regs.r11; | ||
| 2769 | + env->regs[12] = sc->regs.r12; | ||
| 2770 | + env->regs[13] = sc->regs.r13; | ||
| 2771 | + env->regs[14] = sc->usp; | ||
| 2772 | + env->regs[15] = sc->regs.acr; | ||
| 2773 | +} | ||
| 2774 | + | ||
| 2775 | +static struct target_signal_frame *get_sigframe(CPUState *env, int framesize) | ||
| 2776 | +{ | ||
| 2777 | + uint8_t *sp; | ||
| 2778 | + /* Align the stack downwards to 4. */ | ||
| 2779 | + sp = (uint8_t *) (env->regs[R_SP] & ~3); | ||
| 2780 | + return (void *)(sp - framesize); | ||
| 2781 | +} | ||
| 2782 | + | ||
| 2783 | +static void setup_frame(int sig, struct emulated_sigaction *ka, | ||
| 2784 | + target_sigset_t *set, CPUState *env) | ||
| 2785 | +{ | ||
| 2786 | + struct target_signal_frame *frame; | ||
| 2787 | + int err = 0; | ||
| 2788 | + int i; | ||
| 2789 | + uint32_t old_usp; | ||
| 2790 | + | ||
| 2791 | + old_usp = env->regs[R_SP]; | ||
| 2792 | + | ||
| 2793 | + frame = get_sigframe(env, sizeof *frame); | ||
| 2794 | + if (!lock_user_struct(VERIFY_WRITE, frame, (abi_ulong)frame, 1)) | ||
| 2795 | + goto badframe; | ||
| 2796 | + | ||
| 2797 | + /* | ||
| 2798 | + * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't | ||
| 2799 | + * use this trampoline anymore but it sets it up for GDB. | ||
| 2800 | + * In QEMU, using the trampoline simplifies things a bit so we use it. | ||
| 2801 | + * | ||
| 2802 | + * This is movu.w __NR_sigreturn, r9; break 13; | ||
| 2803 | + */ | ||
| 2804 | + err |= __put_user(0x9c5f, frame->retcode+0); | ||
| 2805 | + err |= __put_user(TARGET_NR_sigreturn, | ||
| 2806 | + frame->retcode+2); | ||
| 2807 | + err |= __put_user(0xe93d, frame->retcode+4); | ||
| 2808 | + | ||
| 2809 | + /* Save the mask. */ | ||
| 2810 | + err |= __put_user(set->sig[0], &frame->sc.oldmask); | ||
| 2811 | + if (err) | ||
| 2812 | + goto badframe; | ||
| 2813 | + | ||
| 2814 | + for(i = 1; i < TARGET_NSIG_WORDS; i++) { | ||
| 2815 | + if (__put_user(set->sig[i], &frame->extramask[i - 1])) | ||
| 2816 | + goto badframe; | ||
| 2817 | + } | ||
| 2818 | + | ||
| 2819 | + setup_sigcontext(&frame->sc, env); | ||
| 2820 | + | ||
| 2821 | + /* Move the stack and setup the arguments for the handler. */ | ||
| 2822 | + env->regs[R_SP] = (uint32_t) frame; | ||
| 2823 | + env->regs[10] = sig; | ||
| 2824 | + env->pc = (unsigned long) ka->sa._sa_handler; | ||
| 2825 | + /* Link SRP so the guest returns through the trampoline. */ | ||
| 2826 | + env->pregs[PR_SRP] = (uint32_t) &frame->retcode[0]; | ||
| 2827 | + | ||
| 2828 | + unlock_user_struct(frame, (abi_ulong)frame, 0); | ||
| 2829 | + return; | ||
| 2830 | + badframe: | ||
| 2831 | + unlock_user_struct(frame, (abi_ulong)frame, 0); | ||
| 2832 | + force_sig(TARGET_SIGSEGV); | ||
| 2833 | +} | ||
| 2834 | + | ||
| 2835 | +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, | ||
| 2836 | + target_siginfo_t *info, | ||
| 2837 | + target_sigset_t *set, CPUState *env) | ||
| 2838 | +{ | ||
| 2839 | + fprintf(stderr, "CRIS setup_rt_frame: not implemented\n"); | ||
| 2840 | +} | ||
| 2841 | + | ||
| 2842 | +long do_sigreturn(CPUState *env) | ||
| 2843 | +{ | ||
| 2844 | + struct target_signal_frame *frame; | ||
| 2845 | + target_sigset_t target_set; | ||
| 2846 | + sigset_t set; | ||
| 2847 | + int i; | ||
| 2848 | + | ||
| 2849 | + frame = (void *) env->regs[R_SP]; | ||
| 2850 | + /* Make sure the guest isn't playing games. */ | ||
| 2851 | + if (!lock_user_struct(VERIFY_READ, frame, (abi_ulong)frame, 1)) | ||
| 2852 | + goto badframe; | ||
| 2853 | + | ||
| 2854 | + /* Restore blocked signals */ | ||
| 2855 | + if (__get_user(target_set.sig[0], &frame->sc.oldmask)) | ||
| 2856 | + goto badframe; | ||
| 2857 | + for(i = 1; i < TARGET_NSIG_WORDS; i++) { | ||
| 2858 | + if (__get_user(target_set.sig[i], &frame->extramask[i - 1])) | ||
| 2859 | + goto badframe; | ||
| 2860 | + } | ||
| 2861 | + target_to_host_sigset_internal(&set, &target_set); | ||
| 2862 | + sigprocmask(SIG_SETMASK, &set, NULL); | ||
| 2863 | + | ||
| 2864 | + restore_sigcontext(&frame->sc, env); | ||
| 2865 | + /* Compensate -2 for the syscall return path advancing brk. */ | ||
| 2866 | + env->pc = frame->sc.regs.erp - 2; | ||
| 2867 | + env->pregs[PR_SRP] = frame->sc.regs.srp; | ||
| 2868 | + | ||
| 2869 | + unlock_user_struct(frame, (abi_ulong)frame, 0); | ||
| 2870 | + return env->regs[10]; | ||
| 2871 | + badframe: | ||
| 2872 | + unlock_user_struct(frame, (abi_ulong)frame, 0); | ||
| 2873 | + force_sig(TARGET_SIGSEGV); | ||
| 2874 | +} | ||
| 2875 | + | ||
| 2876 | +long do_rt_sigreturn(CPUState *env) | ||
| 2877 | +{ | ||
| 2878 | + fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n"); | ||
| 2879 | + return -TARGET_ENOSYS; | ||
| 2880 | +} | ||
| 2709 | 2881 | ||
| 2710 | #else | 2882 | #else |
| 2711 | 2883 |