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 | 1673 | queue_signal(info.si_signo, &info); |
1674 | 1674 | } |
1675 | 1675 | break; |
1676 | + case EXCP_INTERRUPT: | |
1677 | + /* just indicate that signals should be handled asap */ | |
1678 | + break; | |
1676 | 1679 | case EXCP_BREAK: |
1677 | 1680 | ret = do_syscall(env, |
1678 | 1681 | env->regs[9], | ... | ... |
linux-user/signal.c
... | ... | @@ -2706,6 +2706,178 @@ badframe: |
2706 | 2706 | force_sig(TARGET_SIGSEGV); |
2707 | 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 | 2882 | #else |
2711 | 2883 | ... | ... |