Revision a4c075f1 linux-user/signal.c
b/linux-user/signal.c | ||
---|---|---|
3614 | 3614 |
return -TARGET_ENOSYS; |
3615 | 3615 |
} |
3616 | 3616 |
|
3617 |
#elif defined(TARGET_S390X) |
|
3618 |
|
|
3619 |
#define __NUM_GPRS 16 |
|
3620 |
#define __NUM_FPRS 16 |
|
3621 |
#define __NUM_ACRS 16 |
|
3622 |
|
|
3623 |
#define S390_SYSCALL_SIZE 2 |
|
3624 |
#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */ |
|
3625 |
|
|
3626 |
#define _SIGCONTEXT_NSIG 64 |
|
3627 |
#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */ |
|
3628 |
#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW) |
|
3629 |
#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS) |
|
3630 |
#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */ |
|
3631 |
#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00) |
|
3632 |
|
|
3633 |
typedef struct { |
|
3634 |
target_psw_t psw; |
|
3635 |
target_ulong gprs[__NUM_GPRS]; |
|
3636 |
unsigned int acrs[__NUM_ACRS]; |
|
3637 |
} target_s390_regs_common; |
|
3638 |
|
|
3639 |
typedef struct { |
|
3640 |
unsigned int fpc; |
|
3641 |
double fprs[__NUM_FPRS]; |
|
3642 |
} target_s390_fp_regs; |
|
3643 |
|
|
3644 |
typedef struct { |
|
3645 |
target_s390_regs_common regs; |
|
3646 |
target_s390_fp_regs fpregs; |
|
3647 |
} target_sigregs; |
|
3648 |
|
|
3649 |
struct target_sigcontext { |
|
3650 |
target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS]; |
|
3651 |
target_sigregs *sregs; |
|
3652 |
}; |
|
3653 |
|
|
3654 |
typedef struct { |
|
3655 |
uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; |
|
3656 |
struct target_sigcontext sc; |
|
3657 |
target_sigregs sregs; |
|
3658 |
int signo; |
|
3659 |
uint8_t retcode[S390_SYSCALL_SIZE]; |
|
3660 |
} sigframe; |
|
3661 |
|
|
3662 |
struct target_ucontext { |
|
3663 |
target_ulong uc_flags; |
|
3664 |
struct target_ucontext *uc_link; |
|
3665 |
target_stack_t uc_stack; |
|
3666 |
target_sigregs uc_mcontext; |
|
3667 |
target_sigset_t uc_sigmask; /* mask last for extensibility */ |
|
3668 |
}; |
|
3669 |
|
|
3670 |
typedef struct { |
|
3671 |
uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; |
|
3672 |
uint8_t retcode[S390_SYSCALL_SIZE]; |
|
3673 |
struct target_siginfo info; |
|
3674 |
struct target_ucontext uc; |
|
3675 |
} rt_sigframe; |
|
3676 |
|
|
3677 |
static inline abi_ulong |
|
3678 |
get_sigframe(struct target_sigaction *ka, CPUState *env, size_t frame_size) |
|
3679 |
{ |
|
3680 |
abi_ulong sp; |
|
3681 |
|
|
3682 |
/* Default to using normal stack */ |
|
3683 |
sp = env->regs[15]; |
|
3684 |
|
|
3685 |
/* This is the X/Open sanctioned signal stack switching. */ |
|
3686 |
if (ka->sa_flags & TARGET_SA_ONSTACK) { |
|
3687 |
if (!sas_ss_flags(sp)) { |
|
3688 |
sp = target_sigaltstack_used.ss_sp + |
|
3689 |
target_sigaltstack_used.ss_size; |
|
3690 |
} |
|
3691 |
} |
|
3692 |
|
|
3693 |
/* This is the legacy signal stack switching. */ |
|
3694 |
else if (/* FIXME !user_mode(regs) */ 0 && |
|
3695 |
!(ka->sa_flags & TARGET_SA_RESTORER) && |
|
3696 |
ka->sa_restorer) { |
|
3697 |
sp = (abi_ulong) ka->sa_restorer; |
|
3698 |
} |
|
3699 |
|
|
3700 |
return (sp - frame_size) & -8ul; |
|
3701 |
} |
|
3702 |
|
|
3703 |
static void save_sigregs(CPUState *env, target_sigregs *sregs) |
|
3704 |
{ |
|
3705 |
int i; |
|
3706 |
//save_access_regs(current->thread.acrs); FIXME |
|
3707 |
|
|
3708 |
/* Copy a 'clean' PSW mask to the user to avoid leaking |
|
3709 |
information about whether PER is currently on. */ |
|
3710 |
__put_user(env->psw.mask, &sregs->regs.psw.mask); |
|
3711 |
__put_user(env->psw.addr, &sregs->regs.psw.addr); |
|
3712 |
for (i = 0; i < 16; i++) { |
|
3713 |
__put_user(env->regs[i], &sregs->regs.gprs[i]); |
|
3714 |
} |
|
3715 |
for (i = 0; i < 16; i++) { |
|
3716 |
__put_user(env->aregs[i], &sregs->regs.acrs[i]); |
|
3717 |
} |
|
3718 |
/* |
|
3719 |
* We have to store the fp registers to current->thread.fp_regs |
|
3720 |
* to merge them with the emulated registers. |
|
3721 |
*/ |
|
3722 |
//save_fp_regs(¤t->thread.fp_regs); FIXME |
|
3723 |
for (i = 0; i < 16; i++) { |
|
3724 |
__put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]); |
|
3725 |
} |
|
3726 |
} |
|
3727 |
|
|
3728 |
static void setup_frame(int sig, struct target_sigaction *ka, |
|
3729 |
target_sigset_t *set, CPUState *env) |
|
3730 |
{ |
|
3731 |
sigframe *frame; |
|
3732 |
abi_ulong frame_addr; |
|
3733 |
|
|
3734 |
frame_addr = get_sigframe(ka, env, sizeof(*frame)); |
|
3735 |
qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__, |
|
3736 |
(unsigned long long)frame_addr); |
|
3737 |
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { |
|
3738 |
goto give_sigsegv; |
|
3739 |
} |
|
3740 |
|
|
3741 |
qemu_log("%s: 1\n", __FUNCTION__); |
|
3742 |
if (__put_user(set->sig[0], &frame->sc.oldmask[0])) { |
|
3743 |
goto give_sigsegv; |
|
3744 |
} |
|
3745 |
|
|
3746 |
save_sigregs(env, &frame->sregs); |
|
3747 |
|
|
3748 |
__put_user((abi_ulong)(unsigned long)&frame->sregs, |
|
3749 |
(abi_ulong *)&frame->sc.sregs); |
|
3750 |
|
|
3751 |
/* Set up to return from userspace. If provided, use a stub |
|
3752 |
already in userspace. */ |
|
3753 |
if (ka->sa_flags & TARGET_SA_RESTORER) { |
|
3754 |
env->regs[14] = (unsigned long) |
|
3755 |
ka->sa_restorer | PSW_ADDR_AMODE; |
|
3756 |
} else { |
|
3757 |
env->regs[14] = (unsigned long) |
|
3758 |
frame->retcode | PSW_ADDR_AMODE; |
|
3759 |
if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, |
|
3760 |
(uint16_t *)(frame->retcode))) |
|
3761 |
goto give_sigsegv; |
|
3762 |
} |
|
3763 |
|
|
3764 |
/* Set up backchain. */ |
|
3765 |
if (__put_user(env->regs[15], (abi_ulong *) frame)) { |
|
3766 |
goto give_sigsegv; |
|
3767 |
} |
|
3768 |
|
|
3769 |
/* Set up registers for signal handler */ |
|
3770 |
env->regs[15] = (target_ulong)(unsigned long) frame; |
|
3771 |
env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE; |
|
3772 |
|
|
3773 |
env->regs[2] = sig; //map_signal(sig); |
|
3774 |
env->regs[3] = (target_ulong)(unsigned long) &frame->sc; |
|
3775 |
|
|
3776 |
/* We forgot to include these in the sigcontext. |
|
3777 |
To avoid breaking binary compatibility, they are passed as args. */ |
|
3778 |
env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no; |
|
3779 |
env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr; |
|
3780 |
|
|
3781 |
/* Place signal number on stack to allow backtrace from handler. */ |
|
3782 |
if (__put_user(env->regs[2], (int *) &frame->signo)) { |
|
3783 |
goto give_sigsegv; |
|
3784 |
} |
|
3785 |
unlock_user_struct(frame, frame_addr, 1); |
|
3786 |
return; |
|
3787 |
|
|
3788 |
give_sigsegv: |
|
3789 |
qemu_log("%s: give_sigsegv\n", __FUNCTION__); |
|
3790 |
unlock_user_struct(frame, frame_addr, 1); |
|
3791 |
force_sig(TARGET_SIGSEGV); |
|
3792 |
} |
|
3793 |
|
|
3794 |
static void setup_rt_frame(int sig, struct target_sigaction *ka, |
|
3795 |
target_siginfo_t *info, |
|
3796 |
target_sigset_t *set, CPUState *env) |
|
3797 |
{ |
|
3798 |
int i; |
|
3799 |
rt_sigframe *frame; |
|
3800 |
abi_ulong frame_addr; |
|
3801 |
|
|
3802 |
frame_addr = get_sigframe(ka, env, sizeof *frame); |
|
3803 |
qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__, |
|
3804 |
(unsigned long long)frame_addr); |
|
3805 |
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { |
|
3806 |
goto give_sigsegv; |
|
3807 |
} |
|
3808 |
|
|
3809 |
qemu_log("%s: 1\n", __FUNCTION__); |
|
3810 |
if (copy_siginfo_to_user(&frame->info, info)) { |
|
3811 |
goto give_sigsegv; |
|
3812 |
} |
|
3813 |
|
|
3814 |
/* Create the ucontext. */ |
|
3815 |
__put_user(0, &frame->uc.uc_flags); |
|
3816 |
__put_user((abi_ulong)0, (abi_ulong *)&frame->uc.uc_link); |
|
3817 |
__put_user(target_sigaltstack_used.ss_sp, &frame->uc.uc_stack.ss_sp); |
|
3818 |
__put_user(sas_ss_flags(get_sp_from_cpustate(env)), |
|
3819 |
&frame->uc.uc_stack.ss_flags); |
|
3820 |
__put_user(target_sigaltstack_used.ss_size, &frame->uc.uc_stack.ss_size); |
|
3821 |
save_sigregs(env, &frame->uc.uc_mcontext); |
|
3822 |
for (i = 0; i < TARGET_NSIG_WORDS; i++) { |
|
3823 |
__put_user((abi_ulong)set->sig[i], |
|
3824 |
(abi_ulong *)&frame->uc.uc_sigmask.sig[i]); |
|
3825 |
} |
|
3826 |
|
|
3827 |
/* Set up to return from userspace. If provided, use a stub |
|
3828 |
already in userspace. */ |
|
3829 |
if (ka->sa_flags & TARGET_SA_RESTORER) { |
|
3830 |
env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE; |
|
3831 |
} else { |
|
3832 |
env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE; |
|
3833 |
if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn, |
|
3834 |
(uint16_t *)(frame->retcode))) { |
|
3835 |
goto give_sigsegv; |
|
3836 |
} |
|
3837 |
} |
|
3838 |
|
|
3839 |
/* Set up backchain. */ |
|
3840 |
if (__put_user(env->regs[15], (abi_ulong *) frame)) { |
|
3841 |
goto give_sigsegv; |
|
3842 |
} |
|
3843 |
|
|
3844 |
/* Set up registers for signal handler */ |
|
3845 |
env->regs[15] = (target_ulong)(unsigned long) frame; |
|
3846 |
env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE; |
|
3847 |
|
|
3848 |
env->regs[2] = sig; //map_signal(sig); |
|
3849 |
env->regs[3] = (target_ulong)(unsigned long) &frame->info; |
|
3850 |
env->regs[4] = (target_ulong)(unsigned long) &frame->uc; |
|
3851 |
return; |
|
3852 |
|
|
3853 |
give_sigsegv: |
|
3854 |
qemu_log("%s: give_sigsegv\n", __FUNCTION__); |
|
3855 |
unlock_user_struct(frame, frame_addr, 1); |
|
3856 |
force_sig(TARGET_SIGSEGV); |
|
3857 |
} |
|
3858 |
|
|
3859 |
static int |
|
3860 |
restore_sigregs(CPUState *env, target_sigregs *sc) |
|
3861 |
{ |
|
3862 |
int err = 0; |
|
3863 |
int i; |
|
3864 |
|
|
3865 |
for (i = 0; i < 16; i++) { |
|
3866 |
err |= __get_user(env->regs[i], &sc->regs.gprs[i]); |
|
3867 |
} |
|
3868 |
|
|
3869 |
err |= __get_user(env->psw.mask, &sc->regs.psw.mask); |
|
3870 |
qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n", |
|
3871 |
__FUNCTION__, (unsigned long long)sc->regs.psw.addr, |
|
3872 |
(unsigned long long)env->psw.addr); |
|
3873 |
err |= __get_user(env->psw.addr, &sc->regs.psw.addr); |
|
3874 |
/* FIXME: 31-bit -> | PSW_ADDR_AMODE */ |
|
3875 |
|
|
3876 |
for (i = 0; i < 16; i++) { |
|
3877 |
err |= __get_user(env->aregs[i], &sc->regs.acrs[i]); |
|
3878 |
} |
|
3879 |
for (i = 0; i < 16; i++) { |
|
3880 |
err |= __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]); |
|
3881 |
} |
|
3882 |
|
|
3883 |
return err; |
|
3884 |
} |
|
3885 |
|
|
3886 |
long do_sigreturn(CPUState *env) |
|
3887 |
{ |
|
3888 |
sigframe *frame; |
|
3889 |
abi_ulong frame_addr = env->regs[15]; |
|
3890 |
qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__, |
|
3891 |
(unsigned long long)frame_addr); |
|
3892 |
target_sigset_t target_set; |
|
3893 |
sigset_t set; |
|
3894 |
|
|
3895 |
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { |
|
3896 |
goto badframe; |
|
3897 |
} |
|
3898 |
if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) { |
|
3899 |
goto badframe; |
|
3900 |
} |
|
3901 |
|
|
3902 |
target_to_host_sigset_internal(&set, &target_set); |
|
3903 |
sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */ |
|
3904 |
|
|
3905 |
if (restore_sigregs(env, &frame->sregs)) { |
|
3906 |
goto badframe; |
|
3907 |
} |
|
3908 |
|
|
3909 |
unlock_user_struct(frame, frame_addr, 0); |
|
3910 |
return env->regs[2]; |
|
3911 |
|
|
3912 |
badframe: |
|
3913 |
unlock_user_struct(frame, frame_addr, 0); |
|
3914 |
force_sig(TARGET_SIGSEGV); |
|
3915 |
return 0; |
|
3916 |
} |
|
3917 |
|
|
3918 |
long do_rt_sigreturn(CPUState *env) |
|
3919 |
{ |
|
3920 |
rt_sigframe *frame; |
|
3921 |
abi_ulong frame_addr = env->regs[15]; |
|
3922 |
qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__, |
|
3923 |
(unsigned long long)frame_addr); |
|
3924 |
sigset_t set; |
|
3925 |
|
|
3926 |
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { |
|
3927 |
goto badframe; |
|
3928 |
} |
|
3929 |
target_to_host_sigset(&set, &frame->uc.uc_sigmask); |
|
3930 |
|
|
3931 |
sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */ |
|
3932 |
|
|
3933 |
if (restore_sigregs(env, &frame->uc.uc_mcontext)) { |
|
3934 |
goto badframe; |
|
3935 |
} |
|
3936 |
|
|
3937 |
if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.uc_stack), 0, |
|
3938 |
get_sp_from_cpustate(env)) == -EFAULT) { |
|
3939 |
goto badframe; |
|
3940 |
} |
|
3941 |
unlock_user_struct(frame, frame_addr, 0); |
|
3942 |
return env->regs[2]; |
|
3943 |
|
|
3944 |
badframe: |
|
3945 |
unlock_user_struct(frame, frame_addr, 0); |
|
3946 |
force_sig(TARGET_SIGSEGV); |
|
3947 |
return 0; |
|
3948 |
} |
|
3949 |
|
|
3617 | 3950 |
#elif defined(TARGET_PPC) && !defined(TARGET_PPC64) |
3618 | 3951 |
|
3619 | 3952 |
/* FIXME: Many of the structures are defined for both PPC and PPC64, but |
Also available in: Unified diff