xref: /openbmc/qemu/linux-user/signal.c (revision ca587a8e)
131e31b8aSbellard /*
266fb9763Sbellard  *  Emulation of Linux signals
331e31b8aSbellard  *
431e31b8aSbellard  *  Copyright (c) 2003 Fabrice Bellard
531e31b8aSbellard  *
631e31b8aSbellard  *  This program is free software; you can redistribute it and/or modify
731e31b8aSbellard  *  it under the terms of the GNU General Public License as published by
831e31b8aSbellard  *  the Free Software Foundation; either version 2 of the License, or
931e31b8aSbellard  *  (at your option) any later version.
1031e31b8aSbellard  *
1131e31b8aSbellard  *  This program is distributed in the hope that it will be useful,
1231e31b8aSbellard  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1331e31b8aSbellard  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1431e31b8aSbellard  *  GNU General Public License for more details.
1531e31b8aSbellard  *
1631e31b8aSbellard  *  You should have received a copy of the GNU General Public License
1731e31b8aSbellard  *  along with this program; if not, write to the Free Software
1831e31b8aSbellard  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1931e31b8aSbellard  */
2031e31b8aSbellard #include <stdlib.h>
2131e31b8aSbellard #include <stdio.h>
2266fb9763Sbellard #include <string.h>
2331e31b8aSbellard #include <stdarg.h>
242677e107Sbellard #include <unistd.h>
2531e31b8aSbellard #include <signal.h>
2666fb9763Sbellard #include <errno.h>
2731e31b8aSbellard #include <sys/ucontext.h>
2831e31b8aSbellard 
293ef693a0Sbellard #include "qemu.h"
30992f48a0Sblueswir1 #include "target_signal.h"
3166fb9763Sbellard 
3266fb9763Sbellard //#define DEBUG_SIGNAL
3366fb9763Sbellard 
34249c4c32Sblueswir1 static struct target_sigaltstack target_sigaltstack_used = {
35a04e134aSths     .ss_sp = 0,
36a04e134aSths     .ss_size = 0,
37a04e134aSths     .ss_flags = TARGET_SS_DISABLE,
38a04e134aSths };
39a04e134aSths 
40624f7979Spbrook static struct target_sigaction sigact_table[TARGET_NSIG];
4131e31b8aSbellard 
4266fb9763Sbellard static void host_signal_handler(int host_signum, siginfo_t *info,
4366fb9763Sbellard                                 void *puc);
4466fb9763Sbellard 
459e5f5284Sbellard static uint8_t host_to_target_signal_table[65] = {
469e5f5284Sbellard     [SIGHUP] = TARGET_SIGHUP,
479e5f5284Sbellard     [SIGINT] = TARGET_SIGINT,
489e5f5284Sbellard     [SIGQUIT] = TARGET_SIGQUIT,
499e5f5284Sbellard     [SIGILL] = TARGET_SIGILL,
509e5f5284Sbellard     [SIGTRAP] = TARGET_SIGTRAP,
519e5f5284Sbellard     [SIGABRT] = TARGET_SIGABRT,
5201e3b763Sbellard /*    [SIGIOT] = TARGET_SIGIOT,*/
539e5f5284Sbellard     [SIGBUS] = TARGET_SIGBUS,
549e5f5284Sbellard     [SIGFPE] = TARGET_SIGFPE,
559e5f5284Sbellard     [SIGKILL] = TARGET_SIGKILL,
569e5f5284Sbellard     [SIGUSR1] = TARGET_SIGUSR1,
579e5f5284Sbellard     [SIGSEGV] = TARGET_SIGSEGV,
589e5f5284Sbellard     [SIGUSR2] = TARGET_SIGUSR2,
599e5f5284Sbellard     [SIGPIPE] = TARGET_SIGPIPE,
609e5f5284Sbellard     [SIGALRM] = TARGET_SIGALRM,
619e5f5284Sbellard     [SIGTERM] = TARGET_SIGTERM,
629e5f5284Sbellard #ifdef SIGSTKFLT
639e5f5284Sbellard     [SIGSTKFLT] = TARGET_SIGSTKFLT,
649e5f5284Sbellard #endif
659e5f5284Sbellard     [SIGCHLD] = TARGET_SIGCHLD,
669e5f5284Sbellard     [SIGCONT] = TARGET_SIGCONT,
679e5f5284Sbellard     [SIGSTOP] = TARGET_SIGSTOP,
689e5f5284Sbellard     [SIGTSTP] = TARGET_SIGTSTP,
699e5f5284Sbellard     [SIGTTIN] = TARGET_SIGTTIN,
709e5f5284Sbellard     [SIGTTOU] = TARGET_SIGTTOU,
719e5f5284Sbellard     [SIGURG] = TARGET_SIGURG,
729e5f5284Sbellard     [SIGXCPU] = TARGET_SIGXCPU,
739e5f5284Sbellard     [SIGXFSZ] = TARGET_SIGXFSZ,
749e5f5284Sbellard     [SIGVTALRM] = TARGET_SIGVTALRM,
759e5f5284Sbellard     [SIGPROF] = TARGET_SIGPROF,
769e5f5284Sbellard     [SIGWINCH] = TARGET_SIGWINCH,
779e5f5284Sbellard     [SIGIO] = TARGET_SIGIO,
789e5f5284Sbellard     [SIGPWR] = TARGET_SIGPWR,
799e5f5284Sbellard     [SIGSYS] = TARGET_SIGSYS,
809e5f5284Sbellard     /* next signals stay the same */
81624f7979Spbrook     /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
82624f7979Spbrook        host libpthread signals.  This assumes noone actually uses SIGRTMAX :-/
83624f7979Spbrook        To fix this properly we need to do manual signal delivery multiplexed
84624f7979Spbrook        over a single host signal.  */
85624f7979Spbrook     [__SIGRTMIN] = __SIGRTMAX,
86624f7979Spbrook     [__SIGRTMAX] = __SIGRTMIN,
879e5f5284Sbellard };
889e5f5284Sbellard static uint8_t target_to_host_signal_table[65];
899e5f5284Sbellard 
90a04e134aSths static inline int on_sig_stack(unsigned long sp)
91a04e134aSths {
92a04e134aSths     return (sp - target_sigaltstack_used.ss_sp
93a04e134aSths             < target_sigaltstack_used.ss_size);
94a04e134aSths }
95a04e134aSths 
96a04e134aSths static inline int sas_ss_flags(unsigned long sp)
97a04e134aSths {
98a04e134aSths     return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
99a04e134aSths             : on_sig_stack(sp) ? SS_ONSTACK : 0);
100a04e134aSths }
101a04e134aSths 
10231e31b8aSbellard static inline int host_to_target_signal(int sig)
10331e31b8aSbellard {
1044cb05961Spbrook     if (sig > 64)
1054cb05961Spbrook         return sig;
1069e5f5284Sbellard     return host_to_target_signal_table[sig];
10731e31b8aSbellard }
10831e31b8aSbellard 
1094cb05961Spbrook int target_to_host_signal(int sig)
11031e31b8aSbellard {
1114cb05961Spbrook     if (sig > 64)
1124cb05961Spbrook         return sig;
1139e5f5284Sbellard     return target_to_host_signal_table[sig];
11431e31b8aSbellard }
11531e31b8aSbellard 
116f5545b5cSpbrook static inline void target_sigemptyset(target_sigset_t *set)
117f5545b5cSpbrook {
118f5545b5cSpbrook     memset(set, 0, sizeof(*set));
119f5545b5cSpbrook }
120f5545b5cSpbrook 
121f5545b5cSpbrook static inline void target_sigaddset(target_sigset_t *set, int signum)
122f5545b5cSpbrook {
123f5545b5cSpbrook     signum--;
124f5545b5cSpbrook     abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
125f5545b5cSpbrook     set->sig[signum / TARGET_NSIG_BPW] |= mask;
126f5545b5cSpbrook }
127f5545b5cSpbrook 
128f5545b5cSpbrook static inline int target_sigismember(const target_sigset_t *set, int signum)
129f5545b5cSpbrook {
130f5545b5cSpbrook     signum--;
131f5545b5cSpbrook     abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
132f5545b5cSpbrook     return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
133f5545b5cSpbrook }
134f5545b5cSpbrook 
1359231944dSbellard static void host_to_target_sigset_internal(target_sigset_t *d,
1369231944dSbellard                                            const sigset_t *s)
13766fb9763Sbellard {
13866fb9763Sbellard     int i;
139f5545b5cSpbrook     target_sigemptyset(d);
140f5545b5cSpbrook     for (i = 1; i <= TARGET_NSIG; i++) {
141f5545b5cSpbrook         if (sigismember(s, i)) {
142f5545b5cSpbrook             target_sigaddset(d, host_to_target_signal(i));
1439e5f5284Sbellard         }
14466fb9763Sbellard     }
14566fb9763Sbellard }
14666fb9763Sbellard 
1479231944dSbellard void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
1489231944dSbellard {
1499231944dSbellard     target_sigset_t d1;
1509231944dSbellard     int i;
1519231944dSbellard 
1529231944dSbellard     host_to_target_sigset_internal(&d1, s);
1539231944dSbellard     for(i = 0;i < TARGET_NSIG_WORDS; i++)
15453a5960aSpbrook         d->sig[i] = tswapl(d1.sig[i]);
1559231944dSbellard }
1569231944dSbellard 
1578fcd3692Sblueswir1 static void target_to_host_sigset_internal(sigset_t *d,
1588fcd3692Sblueswir1                                            const target_sigset_t *s)
15966fb9763Sbellard {
16066fb9763Sbellard     int i;
161f5545b5cSpbrook     sigemptyset(d);
162f5545b5cSpbrook     for (i = 1; i <= TARGET_NSIG; i++) {
163f5545b5cSpbrook         if (target_sigismember(s, i)) {
164f5545b5cSpbrook             sigaddset(d, target_to_host_signal(i));
1659e5f5284Sbellard         }
16666fb9763Sbellard      }
16766fb9763Sbellard }
16866fb9763Sbellard 
1699231944dSbellard void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
1709231944dSbellard {
1719231944dSbellard     target_sigset_t s1;
1729231944dSbellard     int i;
1739231944dSbellard 
1749231944dSbellard     for(i = 0;i < TARGET_NSIG_WORDS; i++)
17553a5960aSpbrook         s1.sig[i] = tswapl(s->sig[i]);
1769231944dSbellard     target_to_host_sigset_internal(d, &s1);
1779231944dSbellard }
1789231944dSbellard 
179992f48a0Sblueswir1 void host_to_target_old_sigset(abi_ulong *old_sigset,
18066fb9763Sbellard                                const sigset_t *sigset)
18166fb9763Sbellard {
1829e5f5284Sbellard     target_sigset_t d;
1839e5f5284Sbellard     host_to_target_sigset(&d, sigset);
1849e5f5284Sbellard     *old_sigset = d.sig[0];
18566fb9763Sbellard }
18666fb9763Sbellard 
18766fb9763Sbellard void target_to_host_old_sigset(sigset_t *sigset,
188992f48a0Sblueswir1                                const abi_ulong *old_sigset)
18966fb9763Sbellard {
1909e5f5284Sbellard     target_sigset_t d;
1919e5f5284Sbellard     int i;
1929e5f5284Sbellard 
1939e5f5284Sbellard     d.sig[0] = *old_sigset;
1949e5f5284Sbellard     for(i = 1;i < TARGET_NSIG_WORDS; i++)
1959e5f5284Sbellard         d.sig[i] = 0;
1969e5f5284Sbellard     target_to_host_sigset(sigset, &d);
19766fb9763Sbellard }
19866fb9763Sbellard 
1999de5e440Sbellard /* siginfo conversion */
2009de5e440Sbellard 
2019de5e440Sbellard static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
2029de5e440Sbellard                                                  const siginfo_t *info)
20366fb9763Sbellard {
2049de5e440Sbellard     int sig;
2059de5e440Sbellard     sig = host_to_target_signal(info->si_signo);
2069de5e440Sbellard     tinfo->si_signo = sig;
2079de5e440Sbellard     tinfo->si_errno = 0;
208afd7cd92Spbrook     tinfo->si_code = info->si_code;
209447db213Sbellard     if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
210447db213Sbellard         sig == SIGBUS || sig == SIGTRAP) {
2119de5e440Sbellard         /* should never come here, but who knows. The information for
2129de5e440Sbellard            the target is irrelevant */
2139de5e440Sbellard         tinfo->_sifields._sigfault._addr = 0;
2147f7f7c84Sths     } else if (sig == SIGIO) {
2157f7f7c84Sths 	tinfo->_sifields._sigpoll._fd = info->si_fd;
2169de5e440Sbellard     } else if (sig >= TARGET_SIGRTMIN) {
2179de5e440Sbellard         tinfo->_sifields._rt._pid = info->si_pid;
2189de5e440Sbellard         tinfo->_sifields._rt._uid = info->si_uid;
2199de5e440Sbellard         /* XXX: potential problem if 64 bit */
2209de5e440Sbellard         tinfo->_sifields._rt._sigval.sival_ptr =
221459a4017Sbellard             (abi_ulong)(unsigned long)info->si_value.sival_ptr;
2229de5e440Sbellard     }
22366fb9763Sbellard }
22466fb9763Sbellard 
2259de5e440Sbellard static void tswap_siginfo(target_siginfo_t *tinfo,
2269de5e440Sbellard                           const target_siginfo_t *info)
2279de5e440Sbellard {
2289de5e440Sbellard     int sig;
2299de5e440Sbellard     sig = info->si_signo;
2309de5e440Sbellard     tinfo->si_signo = tswap32(sig);
2319de5e440Sbellard     tinfo->si_errno = tswap32(info->si_errno);
2329de5e440Sbellard     tinfo->si_code = tswap32(info->si_code);
233447db213Sbellard     if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
234447db213Sbellard         sig == SIGBUS || sig == SIGTRAP) {
2359de5e440Sbellard         tinfo->_sifields._sigfault._addr =
2369de5e440Sbellard             tswapl(info->_sifields._sigfault._addr);
2377f7f7c84Sths     } else if (sig == SIGIO) {
2387f7f7c84Sths 	tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
2399de5e440Sbellard     } else if (sig >= TARGET_SIGRTMIN) {
2409de5e440Sbellard         tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
2419de5e440Sbellard         tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
2429de5e440Sbellard         tinfo->_sifields._rt._sigval.sival_ptr =
2439de5e440Sbellard             tswapl(info->_sifields._rt._sigval.sival_ptr);
2449de5e440Sbellard     }
2459de5e440Sbellard }
2469de5e440Sbellard 
2479de5e440Sbellard 
2489de5e440Sbellard void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
2499de5e440Sbellard {
2509de5e440Sbellard     host_to_target_siginfo_noswap(tinfo, info);
2519de5e440Sbellard     tswap_siginfo(tinfo, tinfo);
2529de5e440Sbellard }
2539de5e440Sbellard 
2549de5e440Sbellard /* XXX: we support only POSIX RT signals are used. */
255aa1f17c1Sths /* XXX: find a solution for 64 bit (additional malloced data is needed) */
2569de5e440Sbellard void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
25766fb9763Sbellard {
25866fb9763Sbellard     info->si_signo = tswap32(tinfo->si_signo);
25966fb9763Sbellard     info->si_errno = tswap32(tinfo->si_errno);
26066fb9763Sbellard     info->si_code = tswap32(tinfo->si_code);
2619de5e440Sbellard     info->si_pid = tswap32(tinfo->_sifields._rt._pid);
2629de5e440Sbellard     info->si_uid = tswap32(tinfo->_sifields._rt._uid);
2639de5e440Sbellard     info->si_value.sival_ptr =
264459a4017Sbellard             (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
26566fb9763Sbellard }
26666fb9763Sbellard 
267*ca587a8eSaurel32 static int fatal_signal (int sig)
268*ca587a8eSaurel32 {
269*ca587a8eSaurel32     switch (sig) {
270*ca587a8eSaurel32     case TARGET_SIGCHLD:
271*ca587a8eSaurel32     case TARGET_SIGURG:
272*ca587a8eSaurel32     case TARGET_SIGWINCH:
273*ca587a8eSaurel32         /* Ignored by default.  */
274*ca587a8eSaurel32         return 0;
275*ca587a8eSaurel32     case TARGET_SIGCONT:
276*ca587a8eSaurel32     case TARGET_SIGSTOP:
277*ca587a8eSaurel32     case TARGET_SIGTSTP:
278*ca587a8eSaurel32     case TARGET_SIGTTIN:
279*ca587a8eSaurel32     case TARGET_SIGTTOU:
280*ca587a8eSaurel32         /* Job control signals.  */
281*ca587a8eSaurel32         return 0;
282*ca587a8eSaurel32     default:
283*ca587a8eSaurel32         return 1;
284*ca587a8eSaurel32     }
285*ca587a8eSaurel32 }
286*ca587a8eSaurel32 
28731e31b8aSbellard void signal_init(void)
28831e31b8aSbellard {
28931e31b8aSbellard     struct sigaction act;
290624f7979Spbrook     struct sigaction oact;
2919e5f5284Sbellard     int i, j;
292624f7979Spbrook     int host_sig;
2939e5f5284Sbellard 
2949e5f5284Sbellard     /* generate signal conversion tables */
2959e5f5284Sbellard     for(i = 1; i <= 64; i++) {
2969e5f5284Sbellard         if (host_to_target_signal_table[i] == 0)
2979e5f5284Sbellard             host_to_target_signal_table[i] = i;
2989e5f5284Sbellard     }
2999e5f5284Sbellard     for(i = 1; i <= 64; i++) {
3009e5f5284Sbellard         j = host_to_target_signal_table[i];
3019e5f5284Sbellard         target_to_host_signal_table[j] = i;
3029e5f5284Sbellard     }
30331e31b8aSbellard 
3049de5e440Sbellard     /* set all host signal handlers. ALL signals are blocked during
3059de5e440Sbellard        the handlers to serialize them. */
306624f7979Spbrook     memset(sigact_table, 0, sizeof(sigact_table));
307624f7979Spbrook 
3089de5e440Sbellard     sigfillset(&act.sa_mask);
30931e31b8aSbellard     act.sa_flags = SA_SIGINFO;
31031e31b8aSbellard     act.sa_sigaction = host_signal_handler;
311624f7979Spbrook     for(i = 1; i <= TARGET_NSIG; i++) {
312624f7979Spbrook         host_sig = target_to_host_signal(i);
313624f7979Spbrook         sigaction(host_sig, NULL, &oact);
314624f7979Spbrook         if (oact.sa_sigaction == (void *)SIG_IGN) {
315624f7979Spbrook             sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
316624f7979Spbrook         } else if (oact.sa_sigaction == (void *)SIG_DFL) {
317624f7979Spbrook             sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
31831e31b8aSbellard         }
319624f7979Spbrook         /* If there's already a handler installed then something has
320624f7979Spbrook            gone horribly wrong, so don't even try to handle that case.  */
321*ca587a8eSaurel32         /* Install some handlers for our own use.  We need at least
322*ca587a8eSaurel32            SIGSEGV and SIGBUS, to detect exceptions.  We can not just
323*ca587a8eSaurel32            trap all signals because it affects syscall interrupt
324*ca587a8eSaurel32            behavior.  But do trap all default-fatal signals.  */
325*ca587a8eSaurel32         if (fatal_signal (i))
326624f7979Spbrook             sigaction(host_sig, &act, NULL);
327624f7979Spbrook     }
328624f7979Spbrook }
32931e31b8aSbellard 
33066fb9763Sbellard /* signal queue handling */
33166fb9763Sbellard 
332624f7979Spbrook static inline struct sigqueue *alloc_sigqueue(CPUState *env)
33366fb9763Sbellard {
334624f7979Spbrook     TaskState *ts = env->opaque;
335624f7979Spbrook     struct sigqueue *q = ts->first_free;
33666fb9763Sbellard     if (!q)
33766fb9763Sbellard         return NULL;
338624f7979Spbrook     ts->first_free = q->next;
33966fb9763Sbellard     return q;
34066fb9763Sbellard }
34166fb9763Sbellard 
342624f7979Spbrook static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
34366fb9763Sbellard {
344624f7979Spbrook     TaskState *ts = env->opaque;
345624f7979Spbrook     q->next = ts->first_free;
346624f7979Spbrook     ts->first_free = q;
34766fb9763Sbellard }
34866fb9763Sbellard 
3499de5e440Sbellard /* abort execution with signal */
3508fcd3692Sblueswir1 static void __attribute((noreturn)) force_sig(int sig)
35166fb9763Sbellard {
3529de5e440Sbellard     int host_sig;
3539de5e440Sbellard     host_sig = target_to_host_signal(sig);
354bc8a22ccSbellard     fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
3559de5e440Sbellard             sig, strsignal(host_sig));
3569de5e440Sbellard #if 1
357*ca587a8eSaurel32     gdb_signalled(thread_env, sig);
3589de5e440Sbellard     _exit(-host_sig);
3599de5e440Sbellard #else
3609de5e440Sbellard     {
3619de5e440Sbellard         struct sigaction act;
3629de5e440Sbellard         sigemptyset(&act.sa_mask);
3639de5e440Sbellard         act.sa_flags = SA_SIGINFO;
3649de5e440Sbellard         act.sa_sigaction = SIG_DFL;
3659de5e440Sbellard         sigaction(SIGABRT, &act, NULL);
3669de5e440Sbellard         abort();
3679de5e440Sbellard     }
3689de5e440Sbellard #endif
3699de5e440Sbellard }
37066fb9763Sbellard 
3719de5e440Sbellard /* queue a signal so that it will be send to the virtual CPU as soon
3729de5e440Sbellard    as possible */
373624f7979Spbrook int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
3749de5e440Sbellard {
375624f7979Spbrook     TaskState *ts = env->opaque;
376624f7979Spbrook     struct emulated_sigtable *k;
3779de5e440Sbellard     struct sigqueue *q, **pq;
378992f48a0Sblueswir1     abi_ulong handler;
379*ca587a8eSaurel32     int queue;
3809de5e440Sbellard 
3819de5e440Sbellard #if defined(DEBUG_SIGNAL)
382bc8a22ccSbellard     fprintf(stderr, "queue_signal: sig=%d\n",
3839de5e440Sbellard             sig);
3849de5e440Sbellard #endif
385624f7979Spbrook     k = &ts->sigtab[sig - 1];
386*ca587a8eSaurel32     queue = gdb_queuesig ();
387624f7979Spbrook     handler = sigact_table[sig - 1]._sa_handler;
388*ca587a8eSaurel32     if (!queue && handler == TARGET_SIG_DFL) {
38960b19691Sths         if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
39060b19691Sths             kill(getpid(),SIGSTOP);
39160b19691Sths             return 0;
39260b19691Sths         } else
3939de5e440Sbellard         /* default handler : ignore some signal. The other are fatal */
3949de5e440Sbellard         if (sig != TARGET_SIGCHLD &&
3959de5e440Sbellard             sig != TARGET_SIGURG &&
39660b19691Sths             sig != TARGET_SIGWINCH &&
39760b19691Sths             sig != TARGET_SIGCONT) {
3989de5e440Sbellard             force_sig(sig);
3999de5e440Sbellard         } else {
4009de5e440Sbellard             return 0; /* indicate ignored */
4019de5e440Sbellard         }
402*ca587a8eSaurel32     } else if (!queue && handler == TARGET_SIG_IGN) {
4039de5e440Sbellard         /* ignore signal */
4049de5e440Sbellard         return 0;
405*ca587a8eSaurel32     } else if (!queue && handler == TARGET_SIG_ERR) {
4069de5e440Sbellard         force_sig(sig);
4079de5e440Sbellard     } else {
40866fb9763Sbellard         pq = &k->first;
4099de5e440Sbellard         if (sig < TARGET_SIGRTMIN) {
4109de5e440Sbellard             /* if non real time signal, we queue exactly one signal */
4119de5e440Sbellard             if (!k->pending)
4129de5e440Sbellard                 q = &k->info;
4139de5e440Sbellard             else
4149de5e440Sbellard                 return 0;
4159de5e440Sbellard         } else {
4169de5e440Sbellard             if (!k->pending) {
4179de5e440Sbellard                 /* first signal */
41866fb9763Sbellard                 q = &k->info;
41966fb9763Sbellard             } else {
420624f7979Spbrook                 q = alloc_sigqueue(env);
42166fb9763Sbellard                 if (!q)
42266fb9763Sbellard                     return -EAGAIN;
42366fb9763Sbellard                 while (*pq != NULL)
42466fb9763Sbellard                     pq = &(*pq)->next;
42566fb9763Sbellard             }
4269de5e440Sbellard         }
42766fb9763Sbellard         *pq = q;
42866fb9763Sbellard         q->info = *info;
42966fb9763Sbellard         q->next = NULL;
43066fb9763Sbellard         k->pending = 1;
43166fb9763Sbellard         /* signal that a new signal is pending */
432624f7979Spbrook         ts->signal_pending = 1;
4339de5e440Sbellard         return 1; /* indicates that the signal was queued */
4349de5e440Sbellard     }
43566fb9763Sbellard }
43666fb9763Sbellard 
43731e31b8aSbellard static void host_signal_handler(int host_signum, siginfo_t *info,
43831e31b8aSbellard                                 void *puc)
43931e31b8aSbellard {
44066fb9763Sbellard     int sig;
4419de5e440Sbellard     target_siginfo_t tinfo;
4429de5e440Sbellard 
4439de5e440Sbellard     /* the CPU emulator uses some host signals to detect exceptions,
4449de5e440Sbellard        we we forward to it some signals */
445*ca587a8eSaurel32     if ((host_signum == SIGSEGV || host_signum == SIGBUS)
446*ca587a8eSaurel32         && info->si_code == SI_KERNEL) {
447b346ff46Sbellard         if (cpu_signal_handler(host_signum, info, puc))
4489de5e440Sbellard             return;
4499de5e440Sbellard     }
45066fb9763Sbellard 
45131e31b8aSbellard     /* get target signal number */
45266fb9763Sbellard     sig = host_to_target_signal(host_signum);
45366fb9763Sbellard     if (sig < 1 || sig > TARGET_NSIG)
45431e31b8aSbellard         return;
4559de5e440Sbellard #if defined(DEBUG_SIGNAL)
456bc8a22ccSbellard     fprintf(stderr, "qemu: got signal %d\n", sig);
45766fb9763Sbellard #endif
4589de5e440Sbellard     host_to_target_siginfo_noswap(&tinfo, info);
459d5975363Spbrook     if (queue_signal(thread_env, sig, &tinfo) == 1) {
4609de5e440Sbellard         /* interrupt the virtual CPU as soon as possible */
461d5975363Spbrook         cpu_interrupt(thread_env, CPU_INTERRUPT_EXIT);
46266fb9763Sbellard     }
46331e31b8aSbellard }
46431e31b8aSbellard 
4650da46a6eSths /* do_sigaltstack() returns target values and errnos. */
466579a97f7Sbellard /* compare linux/kernel/signal.c:do_sigaltstack() */
467579a97f7Sbellard abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
468a04e134aSths {
469a04e134aSths     int ret;
470a04e134aSths     struct target_sigaltstack oss;
471a04e134aSths 
472a04e134aSths     /* XXX: test errors */
473579a97f7Sbellard     if(uoss_addr)
474a04e134aSths     {
475a04e134aSths         __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
476a04e134aSths         __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
477a04e134aSths         __put_user(sas_ss_flags(sp), &oss.ss_flags);
478a04e134aSths     }
479a04e134aSths 
480579a97f7Sbellard     if(uss_addr)
481a04e134aSths     {
482579a97f7Sbellard         struct target_sigaltstack *uss;
483a04e134aSths         struct target_sigaltstack ss;
484a04e134aSths 
4850da46a6eSths 	ret = -TARGET_EFAULT;
486579a97f7Sbellard         if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
487a04e134aSths 	    || __get_user(ss.ss_sp, &uss->ss_sp)
488a04e134aSths 	    || __get_user(ss.ss_size, &uss->ss_size)
489a04e134aSths 	    || __get_user(ss.ss_flags, &uss->ss_flags))
490a04e134aSths             goto out;
491579a97f7Sbellard         unlock_user_struct(uss, uss_addr, 0);
492a04e134aSths 
4930da46a6eSths 	ret = -TARGET_EPERM;
494a04e134aSths 	if (on_sig_stack(sp))
495a04e134aSths             goto out;
496a04e134aSths 
4970da46a6eSths 	ret = -TARGET_EINVAL;
498a04e134aSths 	if (ss.ss_flags != TARGET_SS_DISABLE
499a04e134aSths             && ss.ss_flags != TARGET_SS_ONSTACK
500a04e134aSths             && ss.ss_flags != 0)
501a04e134aSths             goto out;
502a04e134aSths 
503a04e134aSths 	if (ss.ss_flags == TARGET_SS_DISABLE) {
504a04e134aSths             ss.ss_size = 0;
505a04e134aSths             ss.ss_sp = 0;
506a04e134aSths 	} else {
5070da46a6eSths             ret = -TARGET_ENOMEM;
508a04e134aSths             if (ss.ss_size < MINSIGSTKSZ)
509a04e134aSths                 goto out;
510a04e134aSths 	}
511a04e134aSths 
512a04e134aSths         target_sigaltstack_used.ss_sp = ss.ss_sp;
513a04e134aSths         target_sigaltstack_used.ss_size = ss.ss_size;
514a04e134aSths     }
515a04e134aSths 
516579a97f7Sbellard     if (uoss_addr) {
5170da46a6eSths         ret = -TARGET_EFAULT;
518579a97f7Sbellard         if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
519a04e134aSths             goto out;
520a04e134aSths     }
521a04e134aSths 
522a04e134aSths     ret = 0;
523a04e134aSths out:
524a04e134aSths     return ret;
525a04e134aSths }
526a04e134aSths 
5270da46a6eSths /* do_sigaction() return host values and errnos */
52866fb9763Sbellard int do_sigaction(int sig, const struct target_sigaction *act,
52966fb9763Sbellard                  struct target_sigaction *oact)
53031e31b8aSbellard {
531624f7979Spbrook     struct target_sigaction *k;
532773b93eeSbellard     struct sigaction act1;
533773b93eeSbellard     int host_sig;
5340da46a6eSths     int ret = 0;
53531e31b8aSbellard 
5362a913eb1Sths     if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
53766fb9763Sbellard         return -EINVAL;
53866fb9763Sbellard     k = &sigact_table[sig - 1];
539773b93eeSbellard #if defined(DEBUG_SIGNAL)
54066fb9763Sbellard     fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
54166fb9763Sbellard             sig, (int)act, (int)oact);
54266fb9763Sbellard #endif
54366fb9763Sbellard     if (oact) {
544624f7979Spbrook         oact->_sa_handler = tswapl(k->_sa_handler);
545624f7979Spbrook         oact->sa_flags = tswapl(k->sa_flags);
546106ec879Sbellard #if !defined(TARGET_MIPS)
547624f7979Spbrook         oact->sa_restorer = tswapl(k->sa_restorer);
548106ec879Sbellard #endif
549624f7979Spbrook         oact->sa_mask = k->sa_mask;
55066fb9763Sbellard     }
55166fb9763Sbellard     if (act) {
552624f7979Spbrook         /* FIXME: This is not threadsafe.  */
553624f7979Spbrook         k->_sa_handler = tswapl(act->_sa_handler);
554624f7979Spbrook         k->sa_flags = tswapl(act->sa_flags);
555106ec879Sbellard #if !defined(TARGET_MIPS)
556624f7979Spbrook         k->sa_restorer = tswapl(act->sa_restorer);
557106ec879Sbellard #endif
558624f7979Spbrook         k->sa_mask = act->sa_mask;
559773b93eeSbellard 
560773b93eeSbellard         /* we update the host linux signal state */
561773b93eeSbellard         host_sig = target_to_host_signal(sig);
562773b93eeSbellard         if (host_sig != SIGSEGV && host_sig != SIGBUS) {
563773b93eeSbellard             sigfillset(&act1.sa_mask);
564773b93eeSbellard             act1.sa_flags = SA_SIGINFO;
565624f7979Spbrook             if (k->sa_flags & TARGET_SA_RESTART)
566773b93eeSbellard                 act1.sa_flags |= SA_RESTART;
567773b93eeSbellard             /* NOTE: it is important to update the host kernel signal
568773b93eeSbellard                ignore state to avoid getting unexpected interrupted
569773b93eeSbellard                syscalls */
570624f7979Spbrook             if (k->_sa_handler == TARGET_SIG_IGN) {
571773b93eeSbellard                 act1.sa_sigaction = (void *)SIG_IGN;
572624f7979Spbrook             } else if (k->_sa_handler == TARGET_SIG_DFL) {
573*ca587a8eSaurel32                 if (fatal_signal (sig))
574*ca587a8eSaurel32                     act1.sa_sigaction = host_signal_handler;
575*ca587a8eSaurel32                 else
576773b93eeSbellard                     act1.sa_sigaction = (void *)SIG_DFL;
577773b93eeSbellard             } else {
578773b93eeSbellard                 act1.sa_sigaction = host_signal_handler;
579773b93eeSbellard             }
5800da46a6eSths             ret = sigaction(host_sig, &act1, NULL);
581773b93eeSbellard         }
58266fb9763Sbellard     }
5830da46a6eSths     return ret;
58466fb9763Sbellard }
58566fb9763Sbellard 
58643fff238Sbellard static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
58743fff238Sbellard                                        const target_siginfo_t *info)
58843fff238Sbellard {
58943fff238Sbellard     tswap_siginfo(tinfo, info);
59043fff238Sbellard     return 0;
59143fff238Sbellard }
59243fff238Sbellard 
593c3b5bc8aSths static inline int current_exec_domain_sig(int sig)
594c3b5bc8aSths {
595c3b5bc8aSths     return /* current->exec_domain && current->exec_domain->signal_invmap
596c3b5bc8aSths 	      && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
597c3b5bc8aSths }
598c3b5bc8aSths 
599459a4017Sbellard #if defined(TARGET_I386) && TARGET_ABI_BITS == 32
60066fb9763Sbellard 
60166fb9763Sbellard /* from the Linux kernel */
60266fb9763Sbellard 
60366fb9763Sbellard struct target_fpreg {
60466fb9763Sbellard 	uint16_t significand[4];
60566fb9763Sbellard 	uint16_t exponent;
60666fb9763Sbellard };
60766fb9763Sbellard 
60866fb9763Sbellard struct target_fpxreg {
60966fb9763Sbellard 	uint16_t significand[4];
61066fb9763Sbellard 	uint16_t exponent;
61166fb9763Sbellard 	uint16_t padding[3];
61266fb9763Sbellard };
61366fb9763Sbellard 
61466fb9763Sbellard struct target_xmmreg {
615992f48a0Sblueswir1 	abi_ulong element[4];
61666fb9763Sbellard };
61766fb9763Sbellard 
61866fb9763Sbellard struct target_fpstate {
61966fb9763Sbellard 	/* Regular FPU environment */
620992f48a0Sblueswir1         abi_ulong       cw;
621992f48a0Sblueswir1         abi_ulong       sw;
622992f48a0Sblueswir1         abi_ulong       tag;
623992f48a0Sblueswir1         abi_ulong       ipoff;
624992f48a0Sblueswir1         abi_ulong       cssel;
625992f48a0Sblueswir1         abi_ulong       dataoff;
626992f48a0Sblueswir1         abi_ulong       datasel;
62766fb9763Sbellard 	struct target_fpreg	_st[8];
62866fb9763Sbellard 	uint16_t	status;
62966fb9763Sbellard 	uint16_t	magic;		/* 0xffff = regular FPU data only */
63066fb9763Sbellard 
63166fb9763Sbellard 	/* FXSR FPU environment */
632992f48a0Sblueswir1         abi_ulong       _fxsr_env[6];   /* FXSR FPU env is ignored */
633992f48a0Sblueswir1         abi_ulong       mxcsr;
634992f48a0Sblueswir1         abi_ulong       reserved;
63566fb9763Sbellard 	struct target_fpxreg	_fxsr_st[8];	/* FXSR FPU reg data is ignored */
63666fb9763Sbellard 	struct target_xmmreg	_xmm[8];
637992f48a0Sblueswir1         abi_ulong       padding[56];
63866fb9763Sbellard };
63966fb9763Sbellard 
64066fb9763Sbellard #define X86_FXSR_MAGIC		0x0000
64166fb9763Sbellard 
64266fb9763Sbellard struct target_sigcontext {
64366fb9763Sbellard 	uint16_t gs, __gsh;
64466fb9763Sbellard 	uint16_t fs, __fsh;
64566fb9763Sbellard 	uint16_t es, __esh;
64666fb9763Sbellard 	uint16_t ds, __dsh;
647992f48a0Sblueswir1         abi_ulong edi;
648992f48a0Sblueswir1         abi_ulong esi;
649992f48a0Sblueswir1         abi_ulong ebp;
650992f48a0Sblueswir1         abi_ulong esp;
651992f48a0Sblueswir1         abi_ulong ebx;
652992f48a0Sblueswir1         abi_ulong edx;
653992f48a0Sblueswir1         abi_ulong ecx;
654992f48a0Sblueswir1         abi_ulong eax;
655992f48a0Sblueswir1         abi_ulong trapno;
656992f48a0Sblueswir1         abi_ulong err;
657992f48a0Sblueswir1         abi_ulong eip;
65866fb9763Sbellard 	uint16_t cs, __csh;
659992f48a0Sblueswir1         abi_ulong eflags;
660992f48a0Sblueswir1         abi_ulong esp_at_signal;
66166fb9763Sbellard 	uint16_t ss, __ssh;
662992f48a0Sblueswir1         abi_ulong fpstate; /* pointer */
663992f48a0Sblueswir1         abi_ulong oldmask;
664992f48a0Sblueswir1         abi_ulong cr2;
66566fb9763Sbellard };
66666fb9763Sbellard 
66766fb9763Sbellard struct target_ucontext {
668992f48a0Sblueswir1         abi_ulong         tuc_flags;
669992f48a0Sblueswir1         abi_ulong         tuc_link;
670b8076a74Sbellard 	target_stack_t	  tuc_stack;
671b8076a74Sbellard 	struct target_sigcontext tuc_mcontext;
672b8076a74Sbellard 	target_sigset_t	  tuc_sigmask;	/* mask last for extensibility */
67366fb9763Sbellard };
67466fb9763Sbellard 
67566fb9763Sbellard struct sigframe
67666fb9763Sbellard {
677992f48a0Sblueswir1     abi_ulong pretcode;
67866fb9763Sbellard     int sig;
67966fb9763Sbellard     struct target_sigcontext sc;
68066fb9763Sbellard     struct target_fpstate fpstate;
681992f48a0Sblueswir1     abi_ulong extramask[TARGET_NSIG_WORDS-1];
68266fb9763Sbellard     char retcode[8];
68366fb9763Sbellard };
68466fb9763Sbellard 
68566fb9763Sbellard struct rt_sigframe
68666fb9763Sbellard {
687992f48a0Sblueswir1     abi_ulong pretcode;
68866fb9763Sbellard     int sig;
689992f48a0Sblueswir1     abi_ulong pinfo;
690992f48a0Sblueswir1     abi_ulong puc;
69166fb9763Sbellard     struct target_siginfo info;
69266fb9763Sbellard     struct target_ucontext uc;
69366fb9763Sbellard     struct target_fpstate fpstate;
69466fb9763Sbellard     char retcode[8];
69566fb9763Sbellard };
69666fb9763Sbellard 
69766fb9763Sbellard /*
69866fb9763Sbellard  * Set up a signal frame.
69966fb9763Sbellard  */
70066fb9763Sbellard 
70166fb9763Sbellard /* XXX: save x87 state */
70266fb9763Sbellard static int
70366fb9763Sbellard setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
70428be6234Sbellard 		 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
70566fb9763Sbellard {
70666fb9763Sbellard 	int err = 0;
707775b58d8Sbellard         uint16_t magic;
70866fb9763Sbellard 
709579a97f7Sbellard 	/* already locked in setup_frame() */
710a52c757cSbellard 	err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
711a52c757cSbellard 	err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
712a52c757cSbellard 	err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
713a52c757cSbellard 	err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
71466fb9763Sbellard 	err |= __put_user(env->regs[R_EDI], &sc->edi);
71566fb9763Sbellard 	err |= __put_user(env->regs[R_ESI], &sc->esi);
71666fb9763Sbellard 	err |= __put_user(env->regs[R_EBP], &sc->ebp);
71766fb9763Sbellard 	err |= __put_user(env->regs[R_ESP], &sc->esp);
71866fb9763Sbellard 	err |= __put_user(env->regs[R_EBX], &sc->ebx);
71966fb9763Sbellard 	err |= __put_user(env->regs[R_EDX], &sc->edx);
72066fb9763Sbellard 	err |= __put_user(env->regs[R_ECX], &sc->ecx);
72166fb9763Sbellard 	err |= __put_user(env->regs[R_EAX], &sc->eax);
72266099dd9Sbellard 	err |= __put_user(env->exception_index, &sc->trapno);
72366099dd9Sbellard 	err |= __put_user(env->error_code, &sc->err);
72466fb9763Sbellard 	err |= __put_user(env->eip, &sc->eip);
725a52c757cSbellard 	err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
72666fb9763Sbellard 	err |= __put_user(env->eflags, &sc->eflags);
72766fb9763Sbellard 	err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
728a52c757cSbellard 	err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
729ed2dcdf6Sbellard 
73028be6234Sbellard         cpu_x86_fsave(env, fpstate_addr, 1);
731ed2dcdf6Sbellard         fpstate->status = fpstate->sw;
732775b58d8Sbellard         magic = 0xffff;
733775b58d8Sbellard         err |= __put_user(magic, &fpstate->magic);
73428be6234Sbellard         err |= __put_user(fpstate_addr, &sc->fpstate);
735ed2dcdf6Sbellard 
73666fb9763Sbellard 	/* non-iBCS2 extensions.. */
73766fb9763Sbellard 	err |= __put_user(mask, &sc->oldmask);
738a52c757cSbellard 	err |= __put_user(env->cr[2], &sc->cr2);
73966fb9763Sbellard 	return err;
74066fb9763Sbellard }
74166fb9763Sbellard 
74266fb9763Sbellard /*
74366fb9763Sbellard  * Determine which stack to use..
74466fb9763Sbellard  */
74566fb9763Sbellard 
746579a97f7Sbellard static inline abi_ulong
747624f7979Spbrook get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
74866fb9763Sbellard {
74966fb9763Sbellard 	unsigned long esp;
75066fb9763Sbellard 
75166fb9763Sbellard 	/* Default to using normal stack */
75266fb9763Sbellard 	esp = env->regs[R_ESP];
75366fb9763Sbellard 	/* This is the X/Open sanctioned signal stack switching.  */
754624f7979Spbrook         if (ka->sa_flags & TARGET_SA_ONSTACK) {
75566fb9763Sbellard             if (sas_ss_flags(esp) == 0)
756a04e134aSths                 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
75766fb9763Sbellard         }
75866fb9763Sbellard 
75966fb9763Sbellard 	/* This is the legacy signal stack switching. */
760a52c757cSbellard 	else
761a52c757cSbellard         if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
762624f7979Spbrook             !(ka->sa_flags & TARGET_SA_RESTORER) &&
763624f7979Spbrook             ka->sa_restorer) {
764624f7979Spbrook             esp = (unsigned long) ka->sa_restorer;
76566fb9763Sbellard 	}
766579a97f7Sbellard         return (esp - frame_size) & -8ul;
76766fb9763Sbellard }
76866fb9763Sbellard 
769579a97f7Sbellard /* compare linux/arch/i386/kernel/signal.c:setup_frame() */
770624f7979Spbrook static void setup_frame(int sig, struct target_sigaction *ka,
77166fb9763Sbellard 			target_sigset_t *set, CPUX86State *env)
77266fb9763Sbellard {
773579a97f7Sbellard 	abi_ulong frame_addr;
77466fb9763Sbellard 	struct sigframe *frame;
7759231944dSbellard 	int i, err = 0;
77666fb9763Sbellard 
777579a97f7Sbellard 	frame_addr = get_sigframe(ka, env, sizeof(*frame));
77866fb9763Sbellard 
779579a97f7Sbellard 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
78066fb9763Sbellard 		goto give_sigsegv;
781579a97f7Sbellard 
782c3b5bc8aSths 	err |= __put_user(current_exec_domain_sig(sig),
78366fb9763Sbellard 		          &frame->sig);
78466fb9763Sbellard 	if (err)
78566fb9763Sbellard 		goto give_sigsegv;
78666fb9763Sbellard 
78728be6234Sbellard 	setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
78828be6234Sbellard                          frame_addr + offsetof(struct sigframe, fpstate));
78966fb9763Sbellard 	if (err)
79066fb9763Sbellard 		goto give_sigsegv;
79166fb9763Sbellard 
7929231944dSbellard         for(i = 1; i < TARGET_NSIG_WORDS; i++) {
7939231944dSbellard             if (__put_user(set->sig[i], &frame->extramask[i - 1]))
79466fb9763Sbellard                 goto give_sigsegv;
7959231944dSbellard         }
79666fb9763Sbellard 
79766fb9763Sbellard 	/* Set up to return from userspace.  If provided, use a stub
79866fb9763Sbellard 	   already in userspace.  */
799624f7979Spbrook 	if (ka->sa_flags & TARGET_SA_RESTORER) {
800624f7979Spbrook 		err |= __put_user(ka->sa_restorer, &frame->pretcode);
80166fb9763Sbellard 	} else {
802775b58d8Sbellard                 uint16_t val16;
80328be6234Sbellard                 abi_ulong retcode_addr;
80428be6234Sbellard                 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
80528be6234Sbellard 		err |= __put_user(retcode_addr, &frame->pretcode);
80666fb9763Sbellard 		/* This is popl %eax ; movl $,%eax ; int $0x80 */
807775b58d8Sbellard                 val16 = 0xb858;
808775b58d8Sbellard 		err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
80966fb9763Sbellard 		err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
810775b58d8Sbellard                 val16 = 0x80cd;
811775b58d8Sbellard 		err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
81266fb9763Sbellard 	}
81366fb9763Sbellard 
81466fb9763Sbellard 	if (err)
81566fb9763Sbellard 		goto give_sigsegv;
81666fb9763Sbellard 
81766fb9763Sbellard 	/* Set up registers for signal handler */
81828be6234Sbellard 	env->regs[R_ESP] = frame_addr;
819624f7979Spbrook 	env->eip = ka->_sa_handler;
82066fb9763Sbellard 
82166fb9763Sbellard         cpu_x86_load_seg(env, R_DS, __USER_DS);
82266fb9763Sbellard         cpu_x86_load_seg(env, R_ES, __USER_DS);
82366fb9763Sbellard         cpu_x86_load_seg(env, R_SS, __USER_DS);
82466fb9763Sbellard         cpu_x86_load_seg(env, R_CS, __USER_CS);
82566fb9763Sbellard 	env->eflags &= ~TF_MASK;
82666fb9763Sbellard 
827579a97f7Sbellard 	unlock_user_struct(frame, frame_addr, 1);
828579a97f7Sbellard 
82966fb9763Sbellard 	return;
83066fb9763Sbellard 
83166fb9763Sbellard give_sigsegv:
832579a97f7Sbellard 	unlock_user_struct(frame, frame_addr, 1);
83366fb9763Sbellard 	if (sig == TARGET_SIGSEGV)
834624f7979Spbrook 		ka->_sa_handler = TARGET_SIG_DFL;
83566fb9763Sbellard 	force_sig(TARGET_SIGSEGV /* , current */);
83666fb9763Sbellard }
83766fb9763Sbellard 
838579a97f7Sbellard /* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
839624f7979Spbrook static void setup_rt_frame(int sig, struct target_sigaction *ka,
8409de5e440Sbellard                            target_siginfo_t *info,
84166fb9763Sbellard 			   target_sigset_t *set, CPUX86State *env)
84266fb9763Sbellard {
84328be6234Sbellard         abi_ulong frame_addr, addr;
84466fb9763Sbellard 	struct rt_sigframe *frame;
8459231944dSbellard 	int i, err = 0;
84666fb9763Sbellard 
847579a97f7Sbellard 	frame_addr = get_sigframe(ka, env, sizeof(*frame));
84866fb9763Sbellard 
849579a97f7Sbellard 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
85066fb9763Sbellard 		goto give_sigsegv;
85166fb9763Sbellard 
852c3b5bc8aSths 	err |= __put_user(current_exec_domain_sig(sig),
85366fb9763Sbellard 			  &frame->sig);
85428be6234Sbellard         addr = frame_addr + offsetof(struct rt_sigframe, info);
85528be6234Sbellard 	err |= __put_user(addr, &frame->pinfo);
85628be6234Sbellard         addr = frame_addr + offsetof(struct rt_sigframe, uc);
85728be6234Sbellard 	err |= __put_user(addr, &frame->puc);
85866fb9763Sbellard 	err |= copy_siginfo_to_user(&frame->info, info);
85966fb9763Sbellard 	if (err)
86066fb9763Sbellard 		goto give_sigsegv;
86166fb9763Sbellard 
86266fb9763Sbellard 	/* Create the ucontext.  */
863b8076a74Sbellard 	err |= __put_user(0, &frame->uc.tuc_flags);
864b8076a74Sbellard 	err |= __put_user(0, &frame->uc.tuc_link);
865a04e134aSths 	err |= __put_user(target_sigaltstack_used.ss_sp,
866b8076a74Sbellard 			  &frame->uc.tuc_stack.ss_sp);
867a04e134aSths 	err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
868b8076a74Sbellard 			  &frame->uc.tuc_stack.ss_flags);
869a04e134aSths 	err |= __put_user(target_sigaltstack_used.ss_size,
870b8076a74Sbellard 			  &frame->uc.tuc_stack.ss_size);
871b8076a74Sbellard 	err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
87228be6234Sbellard 			        env, set->sig[0],
87328be6234Sbellard                                 frame_addr + offsetof(struct rt_sigframe, fpstate));
8749231944dSbellard         for(i = 0; i < TARGET_NSIG_WORDS; i++) {
875b8076a74Sbellard             if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
87666fb9763Sbellard                 goto give_sigsegv;
8779231944dSbellard         }
87866fb9763Sbellard 
87966fb9763Sbellard 	/* Set up to return from userspace.  If provided, use a stub
88066fb9763Sbellard 	   already in userspace.  */
881624f7979Spbrook 	if (ka->sa_flags & TARGET_SA_RESTORER) {
882624f7979Spbrook 		err |= __put_user(ka->sa_restorer, &frame->pretcode);
88366fb9763Sbellard 	} else {
884775b58d8Sbellard                 uint16_t val16;
88528be6234Sbellard                 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
88628be6234Sbellard 		err |= __put_user(addr, &frame->pretcode);
88766fb9763Sbellard 		/* This is movl $,%eax ; int $0x80 */
88866fb9763Sbellard                 err |= __put_user(0xb8, (char *)(frame->retcode+0));
88966fb9763Sbellard 		err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
890775b58d8Sbellard                 val16 = 0x80cd;
891775b58d8Sbellard                 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
89266fb9763Sbellard 	}
89366fb9763Sbellard 
89466fb9763Sbellard 	if (err)
89566fb9763Sbellard 		goto give_sigsegv;
89666fb9763Sbellard 
89766fb9763Sbellard 	/* Set up registers for signal handler */
89828be6234Sbellard 	env->regs[R_ESP] = frame_addr;
899624f7979Spbrook 	env->eip = ka->_sa_handler;
90066fb9763Sbellard 
90166fb9763Sbellard         cpu_x86_load_seg(env, R_DS, __USER_DS);
90266fb9763Sbellard         cpu_x86_load_seg(env, R_ES, __USER_DS);
90366fb9763Sbellard         cpu_x86_load_seg(env, R_SS, __USER_DS);
90466fb9763Sbellard         cpu_x86_load_seg(env, R_CS, __USER_CS);
90566fb9763Sbellard 	env->eflags &= ~TF_MASK;
90666fb9763Sbellard 
907579a97f7Sbellard 	unlock_user_struct(frame, frame_addr, 1);
908579a97f7Sbellard 
90966fb9763Sbellard 	return;
91066fb9763Sbellard 
91166fb9763Sbellard give_sigsegv:
912579a97f7Sbellard 	unlock_user_struct(frame, frame_addr, 1);
91366fb9763Sbellard 	if (sig == TARGET_SIGSEGV)
914624f7979Spbrook 		ka->_sa_handler = TARGET_SIG_DFL;
91566fb9763Sbellard 	force_sig(TARGET_SIGSEGV /* , current */);
91666fb9763Sbellard }
91766fb9763Sbellard 
91866fb9763Sbellard static int
91966fb9763Sbellard restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
92066fb9763Sbellard {
92166fb9763Sbellard 	unsigned int err = 0;
92228be6234Sbellard         abi_ulong fpstate_addr;
92328be6234Sbellard         unsigned int tmpflags;
92466fb9763Sbellard 
92528be6234Sbellard         cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
92628be6234Sbellard         cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
92728be6234Sbellard         cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
92828be6234Sbellard         cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
92966fb9763Sbellard 
93028be6234Sbellard         env->regs[R_EDI] = tswapl(sc->edi);
93128be6234Sbellard         env->regs[R_ESI] = tswapl(sc->esi);
93228be6234Sbellard         env->regs[R_EBP] = tswapl(sc->ebp);
93328be6234Sbellard         env->regs[R_ESP] = tswapl(sc->esp);
93428be6234Sbellard         env->regs[R_EBX] = tswapl(sc->ebx);
93528be6234Sbellard         env->regs[R_EDX] = tswapl(sc->edx);
93628be6234Sbellard         env->regs[R_ECX] = tswapl(sc->ecx);
93728be6234Sbellard         env->eip = tswapl(sc->eip);
93866fb9763Sbellard 
93966fb9763Sbellard         cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
94066fb9763Sbellard         cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
94166fb9763Sbellard 
94228be6234Sbellard         tmpflags = tswapl(sc->eflags);
94366fb9763Sbellard         env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
94466fb9763Sbellard         //		regs->orig_eax = -1;		/* disable syscall checks */
94566fb9763Sbellard 
94628be6234Sbellard         fpstate_addr = tswapl(sc->fpstate);
94728be6234Sbellard 	if (fpstate_addr != 0) {
94828be6234Sbellard                 if (!access_ok(VERIFY_READ, fpstate_addr,
94928be6234Sbellard                                sizeof(struct target_fpstate)))
95066fb9763Sbellard                         goto badframe;
95128be6234Sbellard                 cpu_x86_frstor(env, fpstate_addr, 1);
952ed2dcdf6Sbellard 	}
953ed2dcdf6Sbellard 
95428be6234Sbellard         *peax = tswapl(sc->eax);
95566fb9763Sbellard 	return err;
95666fb9763Sbellard badframe:
95766fb9763Sbellard 	return 1;
95866fb9763Sbellard }
95966fb9763Sbellard 
96066fb9763Sbellard long do_sigreturn(CPUX86State *env)
96166fb9763Sbellard {
962579a97f7Sbellard     struct sigframe *frame;
963579a97f7Sbellard     abi_ulong frame_addr = env->regs[R_ESP] - 8;
96466fb9763Sbellard     target_sigset_t target_set;
96566fb9763Sbellard     sigset_t set;
96666fb9763Sbellard     int eax, i;
96766fb9763Sbellard 
968447db213Sbellard #if defined(DEBUG_SIGNAL)
969447db213Sbellard     fprintf(stderr, "do_sigreturn\n");
970447db213Sbellard #endif
971579a97f7Sbellard     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
972579a97f7Sbellard         goto badframe;
97366fb9763Sbellard     /* set blocked signals */
9749231944dSbellard     if (__get_user(target_set.sig[0], &frame->sc.oldmask))
9759231944dSbellard         goto badframe;
9769231944dSbellard     for(i = 1; i < TARGET_NSIG_WORDS; i++) {
9779231944dSbellard         if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
9789231944dSbellard             goto badframe;
9799231944dSbellard     }
98066fb9763Sbellard 
9819231944dSbellard     target_to_host_sigset_internal(&set, &target_set);
98266fb9763Sbellard     sigprocmask(SIG_SETMASK, &set, NULL);
98366fb9763Sbellard 
98466fb9763Sbellard     /* restore registers */
98566fb9763Sbellard     if (restore_sigcontext(env, &frame->sc, &eax))
98666fb9763Sbellard         goto badframe;
987579a97f7Sbellard     unlock_user_struct(frame, frame_addr, 0);
98866fb9763Sbellard     return eax;
98966fb9763Sbellard 
99066fb9763Sbellard badframe:
991579a97f7Sbellard     unlock_user_struct(frame, frame_addr, 0);
99266fb9763Sbellard     force_sig(TARGET_SIGSEGV);
99366fb9763Sbellard     return 0;
99466fb9763Sbellard }
99566fb9763Sbellard 
99666fb9763Sbellard long do_rt_sigreturn(CPUX86State *env)
99766fb9763Sbellard {
99828be6234Sbellard         abi_ulong frame_addr;
99928be6234Sbellard 	struct rt_sigframe *frame;
100066fb9763Sbellard         sigset_t set;
100166fb9763Sbellard 	int eax;
100266fb9763Sbellard 
100328be6234Sbellard         frame_addr = env->regs[R_ESP] - 4;
100428be6234Sbellard         if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
100566fb9763Sbellard                 goto badframe;
1006b8076a74Sbellard         target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
100766fb9763Sbellard         sigprocmask(SIG_SETMASK, &set, NULL);
100866fb9763Sbellard 
1009b8076a74Sbellard 	if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
101066fb9763Sbellard 		goto badframe;
101166fb9763Sbellard 
101228be6234Sbellard 	if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
101328be6234Sbellard                            get_sp_from_cpustate(env)) == -EFAULT)
101466fb9763Sbellard 		goto badframe;
1015a04e134aSths 
101628be6234Sbellard         unlock_user_struct(frame, frame_addr, 0);
101766fb9763Sbellard 	return eax;
101866fb9763Sbellard 
101966fb9763Sbellard badframe:
102028be6234Sbellard         unlock_user_struct(frame, frame_addr, 0);
102166fb9763Sbellard         force_sig(TARGET_SIGSEGV);
102266fb9763Sbellard 	return 0;
102366fb9763Sbellard }
102466fb9763Sbellard 
102543fff238Sbellard #elif defined(TARGET_ARM)
102643fff238Sbellard 
102743fff238Sbellard struct target_sigcontext {
1028992f48a0Sblueswir1 	abi_ulong trap_no;
1029992f48a0Sblueswir1 	abi_ulong error_code;
1030992f48a0Sblueswir1 	abi_ulong oldmask;
1031992f48a0Sblueswir1 	abi_ulong arm_r0;
1032992f48a0Sblueswir1 	abi_ulong arm_r1;
1033992f48a0Sblueswir1 	abi_ulong arm_r2;
1034992f48a0Sblueswir1 	abi_ulong arm_r3;
1035992f48a0Sblueswir1 	abi_ulong arm_r4;
1036992f48a0Sblueswir1 	abi_ulong arm_r5;
1037992f48a0Sblueswir1 	abi_ulong arm_r6;
1038992f48a0Sblueswir1 	abi_ulong arm_r7;
1039992f48a0Sblueswir1 	abi_ulong arm_r8;
1040992f48a0Sblueswir1 	abi_ulong arm_r9;
1041992f48a0Sblueswir1 	abi_ulong arm_r10;
1042992f48a0Sblueswir1 	abi_ulong arm_fp;
1043992f48a0Sblueswir1 	abi_ulong arm_ip;
1044992f48a0Sblueswir1 	abi_ulong arm_sp;
1045992f48a0Sblueswir1 	abi_ulong arm_lr;
1046992f48a0Sblueswir1 	abi_ulong arm_pc;
1047992f48a0Sblueswir1 	abi_ulong arm_cpsr;
1048992f48a0Sblueswir1 	abi_ulong fault_address;
104943fff238Sbellard };
105043fff238Sbellard 
1051a745ec6dSpbrook struct target_ucontext_v1 {
1052992f48a0Sblueswir1     abi_ulong tuc_flags;
1053992f48a0Sblueswir1     abi_ulong tuc_link;
1054b8076a74Sbellard     target_stack_t tuc_stack;
1055b8076a74Sbellard     struct target_sigcontext tuc_mcontext;
1056b8076a74Sbellard     target_sigset_t  tuc_sigmask;	/* mask last for extensibility */
105743fff238Sbellard };
105843fff238Sbellard 
1059a745ec6dSpbrook struct target_ucontext_v2 {
1060a745ec6dSpbrook     abi_ulong tuc_flags;
1061a745ec6dSpbrook     abi_ulong tuc_link;
1062a745ec6dSpbrook     target_stack_t tuc_stack;
1063a745ec6dSpbrook     struct target_sigcontext tuc_mcontext;
1064a745ec6dSpbrook     target_sigset_t  tuc_sigmask;	/* mask last for extensibility */
1065a745ec6dSpbrook     char __unused[128 - sizeof(sigset_t)];
1066a745ec6dSpbrook     abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1067a745ec6dSpbrook };
1068a745ec6dSpbrook 
1069a8c33204Spbrook struct sigframe_v1
107043fff238Sbellard {
107143fff238Sbellard     struct target_sigcontext sc;
1072992f48a0Sblueswir1     abi_ulong extramask[TARGET_NSIG_WORDS-1];
1073992f48a0Sblueswir1     abi_ulong retcode;
107443fff238Sbellard };
107543fff238Sbellard 
1076a8c33204Spbrook struct sigframe_v2
1077a8c33204Spbrook {
1078a8c33204Spbrook     struct target_ucontext_v2 uc;
1079a8c33204Spbrook     abi_ulong retcode;
1080a8c33204Spbrook };
1081a8c33204Spbrook 
1082a745ec6dSpbrook struct rt_sigframe_v1
108343fff238Sbellard {
1084f8b0aa25Sbellard     abi_ulong pinfo;
1085f8b0aa25Sbellard     abi_ulong puc;
108643fff238Sbellard     struct target_siginfo info;
1087a745ec6dSpbrook     struct target_ucontext_v1 uc;
1088a745ec6dSpbrook     abi_ulong retcode;
1089a745ec6dSpbrook };
1090a745ec6dSpbrook 
1091a745ec6dSpbrook struct rt_sigframe_v2
1092a745ec6dSpbrook {
1093a745ec6dSpbrook     struct target_siginfo info;
1094a745ec6dSpbrook     struct target_ucontext_v2 uc;
1095992f48a0Sblueswir1     abi_ulong retcode;
109643fff238Sbellard };
109743fff238Sbellard 
109843fff238Sbellard #define TARGET_CONFIG_CPU_32 1
109943fff238Sbellard 
110043fff238Sbellard /*
110143fff238Sbellard  * For ARM syscalls, we encode the syscall number into the instruction.
110243fff238Sbellard  */
110343fff238Sbellard #define SWI_SYS_SIGRETURN	(0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
110443fff238Sbellard #define SWI_SYS_RT_SIGRETURN	(0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
110543fff238Sbellard 
110643fff238Sbellard /*
110743fff238Sbellard  * For Thumb syscalls, we pass the syscall number via r7.  We therefore
110843fff238Sbellard  * need two 16-bit instructions.
110943fff238Sbellard  */
111043fff238Sbellard #define SWI_THUMB_SIGRETURN	(0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
111143fff238Sbellard #define SWI_THUMB_RT_SIGRETURN	(0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
111243fff238Sbellard 
1113992f48a0Sblueswir1 static const abi_ulong retcodes[4] = {
111443fff238Sbellard 	SWI_SYS_SIGRETURN,	SWI_THUMB_SIGRETURN,
111543fff238Sbellard 	SWI_SYS_RT_SIGRETURN,	SWI_THUMB_RT_SIGRETURN
111643fff238Sbellard };
111743fff238Sbellard 
111843fff238Sbellard 
111943fff238Sbellard #define __get_user_error(x,p,e) __get_user(x, p)
112043fff238Sbellard 
112143fff238Sbellard static inline int valid_user_regs(CPUState *regs)
112243fff238Sbellard {
112343fff238Sbellard     return 1;
112443fff238Sbellard }
112543fff238Sbellard 
1126a8c33204Spbrook static void
112743fff238Sbellard setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
1128f8b0aa25Sbellard 		 CPUState *env, abi_ulong mask)
112943fff238Sbellard {
1130a8c33204Spbrook 	__put_user(env->regs[0], &sc->arm_r0);
1131a8c33204Spbrook 	__put_user(env->regs[1], &sc->arm_r1);
1132a8c33204Spbrook 	__put_user(env->regs[2], &sc->arm_r2);
1133a8c33204Spbrook 	__put_user(env->regs[3], &sc->arm_r3);
1134a8c33204Spbrook 	__put_user(env->regs[4], &sc->arm_r4);
1135a8c33204Spbrook 	__put_user(env->regs[5], &sc->arm_r5);
1136a8c33204Spbrook 	__put_user(env->regs[6], &sc->arm_r6);
1137a8c33204Spbrook 	__put_user(env->regs[7], &sc->arm_r7);
1138a8c33204Spbrook 	__put_user(env->regs[8], &sc->arm_r8);
1139a8c33204Spbrook 	__put_user(env->regs[9], &sc->arm_r9);
1140a8c33204Spbrook 	__put_user(env->regs[10], &sc->arm_r10);
1141a8c33204Spbrook 	__put_user(env->regs[11], &sc->arm_fp);
1142a8c33204Spbrook 	__put_user(env->regs[12], &sc->arm_ip);
1143a8c33204Spbrook 	__put_user(env->regs[13], &sc->arm_sp);
1144a8c33204Spbrook 	__put_user(env->regs[14], &sc->arm_lr);
1145a8c33204Spbrook 	__put_user(env->regs[15], &sc->arm_pc);
114643fff238Sbellard #ifdef TARGET_CONFIG_CPU_32
1147a8c33204Spbrook 	__put_user(cpsr_read(env), &sc->arm_cpsr);
114843fff238Sbellard #endif
114943fff238Sbellard 
1150a8c33204Spbrook 	__put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1151a8c33204Spbrook 	__put_user(/* current->thread.error_code */ 0, &sc->error_code);
1152a8c33204Spbrook 	__put_user(/* current->thread.address */ 0, &sc->fault_address);
1153a8c33204Spbrook 	__put_user(mask, &sc->oldmask);
115443fff238Sbellard }
115543fff238Sbellard 
1156579a97f7Sbellard static inline abi_ulong
1157624f7979Spbrook get_sigframe(struct target_sigaction *ka, CPUState *regs, int framesize)
115843fff238Sbellard {
115943fff238Sbellard 	unsigned long sp = regs->regs[13];
116043fff238Sbellard 
116143fff238Sbellard 	/*
116243fff238Sbellard 	 * This is the X/Open sanctioned signal stack switching.
116343fff238Sbellard 	 */
1164624f7979Spbrook 	if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
1165a04e134aSths             sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
116643fff238Sbellard 	/*
116743fff238Sbellard 	 * ATPCS B01 mandates 8-byte alignment
116843fff238Sbellard 	 */
1169579a97f7Sbellard 	return (sp - framesize) & ~7;
117043fff238Sbellard }
117143fff238Sbellard 
117243fff238Sbellard static int
1173624f7979Spbrook setup_return(CPUState *env, struct target_sigaction *ka,
1174f8b0aa25Sbellard 	     abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
117543fff238Sbellard {
1176624f7979Spbrook 	abi_ulong handler = ka->_sa_handler;
1177992f48a0Sblueswir1 	abi_ulong retcode;
117875b680e5Spbrook 	int thumb = handler & 1;
117943fff238Sbellard 
1180624f7979Spbrook 	if (ka->sa_flags & TARGET_SA_RESTORER) {
1181624f7979Spbrook 		retcode = ka->sa_restorer;
118243fff238Sbellard 	} else {
118343fff238Sbellard 		unsigned int idx = thumb;
118443fff238Sbellard 
1185624f7979Spbrook 		if (ka->sa_flags & TARGET_SA_SIGINFO)
118643fff238Sbellard 			idx += 2;
118743fff238Sbellard 
118843fff238Sbellard 		if (__put_user(retcodes[idx], rc))
118943fff238Sbellard 			return 1;
119043fff238Sbellard #if 0
1191992f48a0Sblueswir1 		flush_icache_range((abi_ulong)rc,
1192992f48a0Sblueswir1 				   (abi_ulong)(rc + 1));
119343fff238Sbellard #endif
1194f8b0aa25Sbellard 		retcode = rc_addr + thumb;
119543fff238Sbellard 	}
119643fff238Sbellard 
119743fff238Sbellard 	env->regs[0] = usig;
1198f8b0aa25Sbellard 	env->regs[13] = frame_addr;
119943fff238Sbellard 	env->regs[14] = retcode;
120043fff238Sbellard 	env->regs[15] = handler & (thumb ? ~1 : ~3);
120175b680e5Spbrook 	env->thumb = thumb;
120243fff238Sbellard 
1203b5ff1b31Sbellard #if 0
120443fff238Sbellard #ifdef TARGET_CONFIG_CPU_32
120543fff238Sbellard 	env->cpsr = cpsr;
120643fff238Sbellard #endif
1207b5ff1b31Sbellard #endif
120843fff238Sbellard 
120943fff238Sbellard 	return 0;
121043fff238Sbellard }
121143fff238Sbellard 
1212a8c33204Spbrook static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
1213a8c33204Spbrook                               target_sigset_t *set, CPUState *env)
1214a8c33204Spbrook {
1215a8c33204Spbrook     struct target_sigaltstack stack;
1216a8c33204Spbrook     int i;
1217a8c33204Spbrook 
1218a8c33204Spbrook     /* Clear all the bits of the ucontext we don't use.  */
1219a8c33204Spbrook     memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1220a8c33204Spbrook 
1221a8c33204Spbrook     memset(&stack, 0, sizeof(stack));
1222a8c33204Spbrook     __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1223a8c33204Spbrook     __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1224a8c33204Spbrook     __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1225a8c33204Spbrook     memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1226a8c33204Spbrook 
1227a8c33204Spbrook     setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
1228a8c33204Spbrook     /* FIXME: Save coprocessor signal frame.  */
1229a8c33204Spbrook     for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1230a8c33204Spbrook         __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1231a8c33204Spbrook     }
1232a8c33204Spbrook }
1233a8c33204Spbrook 
1234579a97f7Sbellard /* compare linux/arch/arm/kernel/signal.c:setup_frame() */
1235624f7979Spbrook static void setup_frame_v1(int usig, struct target_sigaction *ka,
123643fff238Sbellard 			   target_sigset_t *set, CPUState *regs)
123743fff238Sbellard {
1238a8c33204Spbrook 	struct sigframe_v1 *frame;
1239579a97f7Sbellard 	abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1240a8c33204Spbrook 	int i;
124143fff238Sbellard 
1242579a97f7Sbellard 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1243579a97f7Sbellard 		return;
1244579a97f7Sbellard 
1245a8c33204Spbrook 	setup_sigcontext(&frame->sc, regs, set->sig[0]);
124643fff238Sbellard 
12479231944dSbellard         for(i = 1; i < TARGET_NSIG_WORDS; i++) {
12489231944dSbellard             if (__put_user(set->sig[i], &frame->extramask[i - 1]))
1249579a97f7Sbellard                 goto end;
125043fff238Sbellard 	}
125143fff238Sbellard 
1252a8c33204Spbrook         setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1253a8c33204Spbrook                      frame_addr + offsetof(struct sigframe_v1, retcode));
1254579a97f7Sbellard 
1255579a97f7Sbellard end:
1256579a97f7Sbellard 	unlock_user_struct(frame, frame_addr, 1);
1257a8c33204Spbrook }
1258a8c33204Spbrook 
1259624f7979Spbrook static void setup_frame_v2(int usig, struct target_sigaction *ka,
1260a8c33204Spbrook 			   target_sigset_t *set, CPUState *regs)
1261a8c33204Spbrook {
1262a8c33204Spbrook 	struct sigframe_v2 *frame;
1263a8c33204Spbrook 	abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1264a8c33204Spbrook 
1265a8c33204Spbrook 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1266a8c33204Spbrook 		return;
1267a8c33204Spbrook 
1268a8c33204Spbrook         setup_sigframe_v2(&frame->uc, set, regs);
1269a8c33204Spbrook 
1270a8c33204Spbrook         setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1271a8c33204Spbrook                      frame_addr + offsetof(struct sigframe_v2, retcode));
1272a8c33204Spbrook 
1273a8c33204Spbrook 	unlock_user_struct(frame, frame_addr, 1);
1274a8c33204Spbrook }
1275a8c33204Spbrook 
1276624f7979Spbrook static void setup_frame(int usig, struct target_sigaction *ka,
1277a8c33204Spbrook 			target_sigset_t *set, CPUState *regs)
1278a8c33204Spbrook {
1279a8c33204Spbrook     if (get_osversion() >= 0x020612) {
1280a8c33204Spbrook         setup_frame_v2(usig, ka, set, regs);
1281a8c33204Spbrook     } else {
1282a8c33204Spbrook         setup_frame_v1(usig, ka, set, regs);
1283a8c33204Spbrook     }
128443fff238Sbellard }
128543fff238Sbellard 
1286579a97f7Sbellard /* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
1287624f7979Spbrook static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
128843fff238Sbellard                               target_siginfo_t *info,
128943fff238Sbellard 			      target_sigset_t *set, CPUState *env)
129043fff238Sbellard {
1291a745ec6dSpbrook 	struct rt_sigframe_v1 *frame;
1292579a97f7Sbellard 	abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1293a04e134aSths 	struct target_sigaltstack stack;
1294a8c33204Spbrook 	int i;
1295f8b0aa25Sbellard         abi_ulong info_addr, uc_addr;
129643fff238Sbellard 
1297579a97f7Sbellard 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1298edf779ffSbellard             return /* 1 */;
1299edf779ffSbellard 
1300a745ec6dSpbrook         info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
1301a8c33204Spbrook 	__put_user(info_addr, &frame->pinfo);
1302a745ec6dSpbrook         uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
1303a8c33204Spbrook 	__put_user(uc_addr, &frame->puc);
1304a8c33204Spbrook 	copy_siginfo_to_user(&frame->info, info);
130543fff238Sbellard 
130643fff238Sbellard 	/* Clear all the bits of the ucontext we don't use.  */
1307a745ec6dSpbrook 	memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
130843fff238Sbellard 
1309a04e134aSths         memset(&stack, 0, sizeof(stack));
1310a04e134aSths         __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1311a04e134aSths         __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1312a04e134aSths         __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1313775b58d8Sbellard         memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
1314a04e134aSths 
1315a8c33204Spbrook 	setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
13169231944dSbellard         for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1317b8076a74Sbellard             if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
1318579a97f7Sbellard                 goto end;
13199231944dSbellard         }
132043fff238Sbellard 
1321a8c33204Spbrook         setup_return(env, ka, &frame->retcode, frame_addr, usig,
1322a745ec6dSpbrook                      frame_addr + offsetof(struct rt_sigframe_v1, retcode));
1323a745ec6dSpbrook 
1324a745ec6dSpbrook         env->regs[1] = info_addr;
1325a745ec6dSpbrook         env->regs[2] = uc_addr;
1326a745ec6dSpbrook 
1327a745ec6dSpbrook end:
1328a745ec6dSpbrook 	unlock_user_struct(frame, frame_addr, 1);
1329a745ec6dSpbrook }
1330a745ec6dSpbrook 
1331624f7979Spbrook static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
1332a745ec6dSpbrook                               target_siginfo_t *info,
1333a745ec6dSpbrook                               target_sigset_t *set, CPUState *env)
1334a745ec6dSpbrook {
1335a745ec6dSpbrook 	struct rt_sigframe_v2 *frame;
1336a745ec6dSpbrook 	abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1337a745ec6dSpbrook         abi_ulong info_addr, uc_addr;
1338a745ec6dSpbrook 
1339a745ec6dSpbrook 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1340a745ec6dSpbrook             return /* 1 */;
1341a745ec6dSpbrook 
1342a745ec6dSpbrook         info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1343a745ec6dSpbrook         uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
1344a8c33204Spbrook 	copy_siginfo_to_user(&frame->info, info);
1345a745ec6dSpbrook 
1346a8c33204Spbrook         setup_sigframe_v2(&frame->uc, set, env);
1347a745ec6dSpbrook 
1348a8c33204Spbrook         setup_return(env, ka, &frame->retcode, frame_addr, usig,
1349a745ec6dSpbrook                      frame_addr + offsetof(struct rt_sigframe_v2, retcode));
135043fff238Sbellard 
1351f8b0aa25Sbellard         env->regs[1] = info_addr;
1352f8b0aa25Sbellard         env->regs[2] = uc_addr;
135343fff238Sbellard 
1354579a97f7Sbellard 	unlock_user_struct(frame, frame_addr, 1);
135543fff238Sbellard }
135643fff238Sbellard 
1357624f7979Spbrook static void setup_rt_frame(int usig, struct target_sigaction *ka,
1358a745ec6dSpbrook                            target_siginfo_t *info,
1359a745ec6dSpbrook 			   target_sigset_t *set, CPUState *env)
1360a745ec6dSpbrook {
1361a745ec6dSpbrook     if (get_osversion() >= 0x020612) {
1362a745ec6dSpbrook         setup_rt_frame_v2(usig, ka, info, set, env);
1363a745ec6dSpbrook     } else {
1364a745ec6dSpbrook         setup_rt_frame_v1(usig, ka, info, set, env);
1365a745ec6dSpbrook     }
1366a745ec6dSpbrook }
1367a745ec6dSpbrook 
136843fff238Sbellard static int
136943fff238Sbellard restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
137043fff238Sbellard {
137143fff238Sbellard 	int err = 0;
1372b5ff1b31Sbellard         uint32_t cpsr;
137343fff238Sbellard 
137443fff238Sbellard 	__get_user_error(env->regs[0], &sc->arm_r0, err);
137543fff238Sbellard 	__get_user_error(env->regs[1], &sc->arm_r1, err);
137643fff238Sbellard 	__get_user_error(env->regs[2], &sc->arm_r2, err);
137743fff238Sbellard 	__get_user_error(env->regs[3], &sc->arm_r3, err);
137843fff238Sbellard 	__get_user_error(env->regs[4], &sc->arm_r4, err);
137943fff238Sbellard 	__get_user_error(env->regs[5], &sc->arm_r5, err);
138043fff238Sbellard 	__get_user_error(env->regs[6], &sc->arm_r6, err);
138143fff238Sbellard 	__get_user_error(env->regs[7], &sc->arm_r7, err);
138243fff238Sbellard 	__get_user_error(env->regs[8], &sc->arm_r8, err);
138343fff238Sbellard 	__get_user_error(env->regs[9], &sc->arm_r9, err);
138443fff238Sbellard 	__get_user_error(env->regs[10], &sc->arm_r10, err);
138543fff238Sbellard 	__get_user_error(env->regs[11], &sc->arm_fp, err);
138643fff238Sbellard 	__get_user_error(env->regs[12], &sc->arm_ip, err);
138743fff238Sbellard 	__get_user_error(env->regs[13], &sc->arm_sp, err);
138843fff238Sbellard 	__get_user_error(env->regs[14], &sc->arm_lr, err);
138943fff238Sbellard 	__get_user_error(env->regs[15], &sc->arm_pc, err);
139043fff238Sbellard #ifdef TARGET_CONFIG_CPU_32
1391b5ff1b31Sbellard 	__get_user_error(cpsr, &sc->arm_cpsr, err);
139275b680e5Spbrook         cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
139343fff238Sbellard #endif
139443fff238Sbellard 
139543fff238Sbellard 	err |= !valid_user_regs(env);
139643fff238Sbellard 
139743fff238Sbellard 	return err;
139843fff238Sbellard }
139943fff238Sbellard 
1400a8c33204Spbrook long do_sigreturn_v1(CPUState *env)
140143fff238Sbellard {
1402f8b0aa25Sbellard         abi_ulong frame_addr;
1403a8c33204Spbrook 	struct sigframe_v1 *frame;
140443fff238Sbellard 	target_sigset_t set;
140543fff238Sbellard         sigset_t host_set;
14069231944dSbellard         int i;
140743fff238Sbellard 
140843fff238Sbellard 	/*
140943fff238Sbellard 	 * Since we stacked the signal on a 64-bit boundary,
141043fff238Sbellard 	 * then 'sp' should be word aligned here.  If it's
141143fff238Sbellard 	 * not, then the user is trying to mess with us.
141243fff238Sbellard 	 */
141343fff238Sbellard 	if (env->regs[13] & 7)
141443fff238Sbellard 		goto badframe;
141543fff238Sbellard 
1416f8b0aa25Sbellard         frame_addr = env->regs[13];
1417f8b0aa25Sbellard 	if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
141843fff238Sbellard                 goto badframe;
1419f8b0aa25Sbellard 
14209231944dSbellard 	if (__get_user(set.sig[0], &frame->sc.oldmask))
142143fff238Sbellard             goto badframe;
14229231944dSbellard         for(i = 1; i < TARGET_NSIG_WORDS; i++) {
14239231944dSbellard             if (__get_user(set.sig[i], &frame->extramask[i - 1]))
14249231944dSbellard                 goto badframe;
14259231944dSbellard         }
142643fff238Sbellard 
14279231944dSbellard         target_to_host_sigset_internal(&host_set, &set);
142843fff238Sbellard         sigprocmask(SIG_SETMASK, &host_set, NULL);
142943fff238Sbellard 
143043fff238Sbellard 	if (restore_sigcontext(env, &frame->sc))
143143fff238Sbellard 		goto badframe;
143243fff238Sbellard 
143343fff238Sbellard #if 0
143443fff238Sbellard 	/* Send SIGTRAP if we're single-stepping */
143543fff238Sbellard 	if (ptrace_cancel_bpt(current))
143643fff238Sbellard 		send_sig(SIGTRAP, current, 1);
143743fff238Sbellard #endif
1438f8b0aa25Sbellard 	unlock_user_struct(frame, frame_addr, 0);
143943fff238Sbellard         return env->regs[0];
144043fff238Sbellard 
144143fff238Sbellard badframe:
1442f8b0aa25Sbellard 	unlock_user_struct(frame, frame_addr, 0);
144343fff238Sbellard         force_sig(SIGSEGV /* , current */);
144443fff238Sbellard 	return 0;
144543fff238Sbellard }
144643fff238Sbellard 
1447a8c33204Spbrook static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr,
1448a8c33204Spbrook                                  struct target_ucontext_v2 *uc)
1449a8c33204Spbrook {
1450a8c33204Spbrook     sigset_t host_set;
1451a8c33204Spbrook 
1452a8c33204Spbrook     target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1453a8c33204Spbrook     sigprocmask(SIG_SETMASK, &host_set, NULL);
1454a8c33204Spbrook 
1455a8c33204Spbrook     if (restore_sigcontext(env, &uc->tuc_mcontext))
1456a8c33204Spbrook         return 1;
1457a8c33204Spbrook 
1458a8c33204Spbrook     if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1459a8c33204Spbrook         return 1;
1460a8c33204Spbrook 
1461a8c33204Spbrook #if 0
1462a8c33204Spbrook     /* Send SIGTRAP if we're single-stepping */
1463a8c33204Spbrook     if (ptrace_cancel_bpt(current))
1464a8c33204Spbrook             send_sig(SIGTRAP, current, 1);
1465a8c33204Spbrook #endif
1466a8c33204Spbrook 
1467a8c33204Spbrook     return 0;
1468a8c33204Spbrook }
1469a8c33204Spbrook 
1470a8c33204Spbrook long do_sigreturn_v2(CPUState *env)
1471a8c33204Spbrook {
1472a8c33204Spbrook         abi_ulong frame_addr;
1473a8c33204Spbrook 	struct sigframe_v2 *frame;
1474a8c33204Spbrook 
1475a8c33204Spbrook 	/*
1476a8c33204Spbrook 	 * Since we stacked the signal on a 64-bit boundary,
1477a8c33204Spbrook 	 * then 'sp' should be word aligned here.  If it's
1478a8c33204Spbrook 	 * not, then the user is trying to mess with us.
1479a8c33204Spbrook 	 */
1480a8c33204Spbrook 	if (env->regs[13] & 7)
1481a8c33204Spbrook 		goto badframe;
1482a8c33204Spbrook 
1483a8c33204Spbrook         frame_addr = env->regs[13];
1484a8c33204Spbrook 	if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1485a8c33204Spbrook                 goto badframe;
1486a8c33204Spbrook 
1487a8c33204Spbrook         if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1488a8c33204Spbrook                 goto badframe;
1489a8c33204Spbrook 
1490a8c33204Spbrook 	unlock_user_struct(frame, frame_addr, 0);
1491a8c33204Spbrook 	return env->regs[0];
1492a8c33204Spbrook 
1493a8c33204Spbrook badframe:
1494a8c33204Spbrook 	unlock_user_struct(frame, frame_addr, 0);
1495a8c33204Spbrook         force_sig(SIGSEGV /* , current */);
1496a8c33204Spbrook 	return 0;
1497a8c33204Spbrook }
1498a8c33204Spbrook 
1499a8c33204Spbrook long do_sigreturn(CPUState *env)
1500a8c33204Spbrook {
1501a8c33204Spbrook     if (get_osversion() >= 0x020612) {
1502a8c33204Spbrook         return do_sigreturn_v2(env);
1503a8c33204Spbrook     } else {
1504a8c33204Spbrook         return do_sigreturn_v1(env);
1505a8c33204Spbrook     }
1506a8c33204Spbrook }
1507a8c33204Spbrook 
1508a745ec6dSpbrook long do_rt_sigreturn_v1(CPUState *env)
150943fff238Sbellard {
1510f8b0aa25Sbellard         abi_ulong frame_addr;
1511a745ec6dSpbrook 	struct rt_sigframe_v1 *frame;
151243fff238Sbellard         sigset_t host_set;
151343fff238Sbellard 
151443fff238Sbellard 	/*
151543fff238Sbellard 	 * Since we stacked the signal on a 64-bit boundary,
151643fff238Sbellard 	 * then 'sp' should be word aligned here.  If it's
151743fff238Sbellard 	 * not, then the user is trying to mess with us.
151843fff238Sbellard 	 */
151943fff238Sbellard 	if (env->regs[13] & 7)
152043fff238Sbellard 		goto badframe;
152143fff238Sbellard 
1522f8b0aa25Sbellard         frame_addr = env->regs[13];
1523f8b0aa25Sbellard 	if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
152443fff238Sbellard                 goto badframe;
1525f8b0aa25Sbellard 
1526b8076a74Sbellard         target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
152743fff238Sbellard         sigprocmask(SIG_SETMASK, &host_set, NULL);
152843fff238Sbellard 
1529b8076a74Sbellard 	if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
153043fff238Sbellard 		goto badframe;
153143fff238Sbellard 
1532a745ec6dSpbrook 	if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1533a04e134aSths 		goto badframe;
1534a04e134aSths 
153543fff238Sbellard #if 0
153643fff238Sbellard 	/* Send SIGTRAP if we're single-stepping */
153743fff238Sbellard 	if (ptrace_cancel_bpt(current))
153843fff238Sbellard 		send_sig(SIGTRAP, current, 1);
153943fff238Sbellard #endif
1540f8b0aa25Sbellard 	unlock_user_struct(frame, frame_addr, 0);
154143fff238Sbellard 	return env->regs[0];
154243fff238Sbellard 
154343fff238Sbellard badframe:
1544f8b0aa25Sbellard 	unlock_user_struct(frame, frame_addr, 0);
154543fff238Sbellard         force_sig(SIGSEGV /* , current */);
154643fff238Sbellard 	return 0;
154743fff238Sbellard }
154843fff238Sbellard 
1549a745ec6dSpbrook long do_rt_sigreturn_v2(CPUState *env)
1550a745ec6dSpbrook {
1551a745ec6dSpbrook         abi_ulong frame_addr;
1552a745ec6dSpbrook 	struct rt_sigframe_v2 *frame;
1553a745ec6dSpbrook 
1554a745ec6dSpbrook 	/*
1555a745ec6dSpbrook 	 * Since we stacked the signal on a 64-bit boundary,
1556a745ec6dSpbrook 	 * then 'sp' should be word aligned here.  If it's
1557a745ec6dSpbrook 	 * not, then the user is trying to mess with us.
1558a745ec6dSpbrook 	 */
1559a745ec6dSpbrook 	if (env->regs[13] & 7)
1560a745ec6dSpbrook 		goto badframe;
1561a745ec6dSpbrook 
1562a745ec6dSpbrook         frame_addr = env->regs[13];
1563a745ec6dSpbrook 	if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1564a745ec6dSpbrook                 goto badframe;
1565a745ec6dSpbrook 
1566a8c33204Spbrook         if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1567a745ec6dSpbrook                 goto badframe;
1568a745ec6dSpbrook 
1569a745ec6dSpbrook 	unlock_user_struct(frame, frame_addr, 0);
1570a745ec6dSpbrook 	return env->regs[0];
1571a745ec6dSpbrook 
1572a745ec6dSpbrook badframe:
1573a745ec6dSpbrook 	unlock_user_struct(frame, frame_addr, 0);
1574a745ec6dSpbrook         force_sig(SIGSEGV /* , current */);
1575a745ec6dSpbrook 	return 0;
1576a745ec6dSpbrook }
1577a745ec6dSpbrook 
1578a745ec6dSpbrook long do_rt_sigreturn(CPUState *env)
1579a745ec6dSpbrook {
1580a745ec6dSpbrook     if (get_osversion() >= 0x020612) {
1581a745ec6dSpbrook         return do_rt_sigreturn_v2(env);
1582a745ec6dSpbrook     } else {
1583a745ec6dSpbrook         return do_rt_sigreturn_v1(env);
1584a745ec6dSpbrook     }
1585a745ec6dSpbrook }
1586a745ec6dSpbrook 
15876d5e216dSbellard #elif defined(TARGET_SPARC)
158880a9d035Sbellard 
15896d5e216dSbellard #define __SUNOS_MAXWIN   31
15906d5e216dSbellard 
15916d5e216dSbellard /* This is what SunOS does, so shall I. */
15926d5e216dSbellard struct target_sigcontext {
1593992f48a0Sblueswir1         abi_ulong sigc_onstack;      /* state to restore */
15946d5e216dSbellard 
1595992f48a0Sblueswir1         abi_ulong sigc_mask;         /* sigmask to restore */
1596992f48a0Sblueswir1         abi_ulong sigc_sp;           /* stack pointer */
1597992f48a0Sblueswir1         abi_ulong sigc_pc;           /* program counter */
1598992f48a0Sblueswir1         abi_ulong sigc_npc;          /* next program counter */
1599992f48a0Sblueswir1         abi_ulong sigc_psr;          /* for condition codes etc */
1600992f48a0Sblueswir1         abi_ulong sigc_g1;           /* User uses these two registers */
1601992f48a0Sblueswir1         abi_ulong sigc_o0;           /* within the trampoline code. */
16026d5e216dSbellard 
16036d5e216dSbellard         /* Now comes information regarding the users window set
16046d5e216dSbellard          * at the time of the signal.
16056d5e216dSbellard          */
1606992f48a0Sblueswir1         abi_ulong sigc_oswins;       /* outstanding windows */
16076d5e216dSbellard 
16086d5e216dSbellard         /* stack ptrs for each regwin buf */
16096d5e216dSbellard         char *sigc_spbuf[__SUNOS_MAXWIN];
16106d5e216dSbellard 
16116d5e216dSbellard         /* Windows to restore after signal */
16126d5e216dSbellard         struct {
1613992f48a0Sblueswir1                 abi_ulong locals[8];
1614992f48a0Sblueswir1                 abi_ulong ins[8];
16156d5e216dSbellard         } sigc_wbuf[__SUNOS_MAXWIN];
16166d5e216dSbellard };
16176d5e216dSbellard /* A Sparc stack frame */
16186d5e216dSbellard struct sparc_stackf {
1619992f48a0Sblueswir1         abi_ulong locals[8];
1620992f48a0Sblueswir1         abi_ulong ins[6];
16216d5e216dSbellard         struct sparc_stackf *fp;
1622992f48a0Sblueswir1         abi_ulong callers_pc;
16236d5e216dSbellard         char *structptr;
1624992f48a0Sblueswir1         abi_ulong xargs[6];
1625992f48a0Sblueswir1         abi_ulong xxargs[1];
16266d5e216dSbellard };
16276d5e216dSbellard 
16286d5e216dSbellard typedef struct {
16296d5e216dSbellard         struct {
1630992f48a0Sblueswir1                 abi_ulong psr;
1631992f48a0Sblueswir1                 abi_ulong pc;
1632992f48a0Sblueswir1                 abi_ulong npc;
1633992f48a0Sblueswir1                 abi_ulong y;
1634992f48a0Sblueswir1                 abi_ulong u_regs[16]; /* globals and ins */
16356d5e216dSbellard         }               si_regs;
16366d5e216dSbellard         int             si_mask;
16376d5e216dSbellard } __siginfo_t;
16386d5e216dSbellard 
16396d5e216dSbellard typedef struct {
16406d5e216dSbellard         unsigned   long si_float_regs [32];
16416d5e216dSbellard         unsigned   long si_fsr;
16426d5e216dSbellard         unsigned   long si_fpqdepth;
16436d5e216dSbellard         struct {
16446d5e216dSbellard                 unsigned long *insn_addr;
16456d5e216dSbellard                 unsigned long insn;
16466d5e216dSbellard         } si_fpqueue [16];
164774ccb34eSbellard } qemu_siginfo_fpu_t;
16486d5e216dSbellard 
16496d5e216dSbellard 
16506d5e216dSbellard struct target_signal_frame {
16516d5e216dSbellard 	struct sparc_stackf	ss;
16526d5e216dSbellard 	__siginfo_t		info;
1653f8b0aa25Sbellard 	abi_ulong               fpu_save;
1654992f48a0Sblueswir1 	abi_ulong		insns[2] __attribute__ ((aligned (8)));
1655992f48a0Sblueswir1 	abi_ulong		extramask[TARGET_NSIG_WORDS - 1];
1656992f48a0Sblueswir1 	abi_ulong		extra_size; /* Should be 0 */
165774ccb34eSbellard 	qemu_siginfo_fpu_t	fpu_state;
16586d5e216dSbellard };
16596d5e216dSbellard struct target_rt_signal_frame {
16606d5e216dSbellard 	struct sparc_stackf	ss;
16616d5e216dSbellard 	siginfo_t		info;
1662992f48a0Sblueswir1 	abi_ulong		regs[20];
16636d5e216dSbellard 	sigset_t		mask;
1664f8b0aa25Sbellard 	abi_ulong               fpu_save;
16656d5e216dSbellard 	unsigned int		insns[2];
16666d5e216dSbellard 	stack_t			stack;
16676d5e216dSbellard 	unsigned int		extra_size; /* Should be 0 */
166874ccb34eSbellard 	qemu_siginfo_fpu_t	fpu_state;
16696d5e216dSbellard };
16706d5e216dSbellard 
1671e80cfcfcSbellard #define UREG_O0        16
1672e80cfcfcSbellard #define UREG_O6        22
1673e80cfcfcSbellard #define UREG_I0        0
1674e80cfcfcSbellard #define UREG_I1        1
1675e80cfcfcSbellard #define UREG_I2        2
16765bfb56b2Sblueswir1 #define UREG_I3        3
16775bfb56b2Sblueswir1 #define UREG_I4        4
16785bfb56b2Sblueswir1 #define UREG_I5        5
1679e80cfcfcSbellard #define UREG_I6        6
1680e80cfcfcSbellard #define UREG_I7        7
1681e80cfcfcSbellard #define UREG_L0	       8
16826d5e216dSbellard #define UREG_FP        UREG_I6
16836d5e216dSbellard #define UREG_SP        UREG_O6
16846d5e216dSbellard 
1685624f7979Spbrook static inline abi_ulong get_sigframe(struct target_sigaction *sa,
1686459a4017Sbellard                                      CPUState *env, unsigned long framesize)
16876d5e216dSbellard {
1688459a4017Sbellard 	abi_ulong sp;
16896d5e216dSbellard 
16906d5e216dSbellard 	sp = env->regwptr[UREG_FP];
16916d5e216dSbellard 
16926d5e216dSbellard 	/* This is the X/Open sanctioned signal stack switching.  */
1693624f7979Spbrook 	if (sa->sa_flags & TARGET_SA_ONSTACK) {
1694a04e134aSths             if (!on_sig_stack(sp)
1695a04e134aSths                 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
1696a04e134aSths                 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
16976d5e216dSbellard 	}
1698459a4017Sbellard 	return sp - framesize;
16996d5e216dSbellard }
17006d5e216dSbellard 
17016d5e216dSbellard static int
1702992f48a0Sblueswir1 setup___siginfo(__siginfo_t *si, CPUState *env, abi_ulong mask)
17036d5e216dSbellard {
17046d5e216dSbellard 	int err = 0, i;
17056d5e216dSbellard 
17066d5e216dSbellard 	err |= __put_user(env->psr, &si->si_regs.psr);
17076d5e216dSbellard 	err |= __put_user(env->pc, &si->si_regs.pc);
17086d5e216dSbellard 	err |= __put_user(env->npc, &si->si_regs.npc);
17096d5e216dSbellard 	err |= __put_user(env->y, &si->si_regs.y);
1710a315a145Sbellard 	for (i=0; i < 8; i++) {
17116d5e216dSbellard 		err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
17126d5e216dSbellard 	}
1713a315a145Sbellard 	for (i=0; i < 8; i++) {
1714e80cfcfcSbellard 		err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
17156d5e216dSbellard 	}
17166d5e216dSbellard 	err |= __put_user(mask, &si->si_mask);
17176d5e216dSbellard 	return err;
17186d5e216dSbellard }
1719e80cfcfcSbellard 
172080a9d035Sbellard #if 0
17216d5e216dSbellard static int
17226d5e216dSbellard setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
17236d5e216dSbellard 		 CPUState *env, unsigned long mask)
17246d5e216dSbellard {
17256d5e216dSbellard 	int err = 0;
17266d5e216dSbellard 
17276d5e216dSbellard 	err |= __put_user(mask, &sc->sigc_mask);
17286d5e216dSbellard 	err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
17296d5e216dSbellard 	err |= __put_user(env->pc, &sc->sigc_pc);
17306d5e216dSbellard 	err |= __put_user(env->npc, &sc->sigc_npc);
17316d5e216dSbellard 	err |= __put_user(env->psr, &sc->sigc_psr);
17326d5e216dSbellard 	err |= __put_user(env->gregs[1], &sc->sigc_g1);
17336d5e216dSbellard 	err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
17346d5e216dSbellard 
17356d5e216dSbellard 	return err;
17366d5e216dSbellard }
173780a9d035Sbellard #endif
17386d5e216dSbellard #define NF_ALIGNEDSZ  (((sizeof(struct target_signal_frame) + 7) & (~7)))
17396d5e216dSbellard 
1740624f7979Spbrook static void setup_frame(int sig, struct target_sigaction *ka,
17416d5e216dSbellard 			target_sigset_t *set, CPUState *env)
17426d5e216dSbellard {
1743459a4017Sbellard         abi_ulong sf_addr;
17446d5e216dSbellard 	struct target_signal_frame *sf;
17456d5e216dSbellard 	int sigframe_size, err, i;
17466d5e216dSbellard 
17476d5e216dSbellard 	/* 1. Make sure everything is clean */
17486d5e216dSbellard 	//synchronize_user_stack();
17496d5e216dSbellard 
17506d5e216dSbellard         sigframe_size = NF_ALIGNEDSZ;
1751459a4017Sbellard 	sf_addr = get_sigframe(ka, env, sigframe_size);
17526d5e216dSbellard 
1753459a4017Sbellard         sf = lock_user(VERIFY_WRITE, sf_addr,
1754459a4017Sbellard                        sizeof(struct target_signal_frame), 0);
1755459a4017Sbellard         if (!sf)
1756459a4017Sbellard 		goto sigsegv;
17576d5e216dSbellard 
1758e80cfcfcSbellard 	//fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
17596d5e216dSbellard #if 0
17606d5e216dSbellard 	if (invalid_frame_pointer(sf, sigframe_size))
17616d5e216dSbellard 		goto sigill_and_return;
17626d5e216dSbellard #endif
17636d5e216dSbellard 	/* 2. Save the current process state */
17646d5e216dSbellard 	err = setup___siginfo(&sf->info, env, set->sig[0]);
17656d5e216dSbellard 	err |= __put_user(0, &sf->extra_size);
17666d5e216dSbellard 
17676d5e216dSbellard 	//err |= save_fpu_state(regs, &sf->fpu_state);
17686d5e216dSbellard 	//err |= __put_user(&sf->fpu_state, &sf->fpu_save);
17696d5e216dSbellard 
17706d5e216dSbellard 	err |= __put_user(set->sig[0], &sf->info.si_mask);
17716d5e216dSbellard 	for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
17726d5e216dSbellard 		err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
17736d5e216dSbellard 	}
17746d5e216dSbellard 
1775a315a145Sbellard 	for (i = 0; i < 8; i++) {
1776e80cfcfcSbellard 	  	err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
17776d5e216dSbellard 	}
1778a315a145Sbellard 	for (i = 0; i < 8; i++) {
1779e80cfcfcSbellard 	  	err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
17806d5e216dSbellard 	}
17816d5e216dSbellard 	if (err)
17826d5e216dSbellard 		goto sigsegv;
17836d5e216dSbellard 
17846d5e216dSbellard 	/* 3. signal handler back-trampoline and parameters */
1785459a4017Sbellard 	env->regwptr[UREG_FP] = sf_addr;
17866d5e216dSbellard 	env->regwptr[UREG_I0] = sig;
1787459a4017Sbellard 	env->regwptr[UREG_I1] = sf_addr +
1788459a4017Sbellard                 offsetof(struct target_signal_frame, info);
1789459a4017Sbellard 	env->regwptr[UREG_I2] = sf_addr +
1790459a4017Sbellard                 offsetof(struct target_signal_frame, info);
17916d5e216dSbellard 
17926d5e216dSbellard 	/* 4. signal handler */
1793624f7979Spbrook 	env->pc = ka->_sa_handler;
17946d5e216dSbellard 	env->npc = (env->pc + 4);
17956d5e216dSbellard 	/* 5. return to kernel instructions */
1796624f7979Spbrook 	if (ka->sa_restorer)
1797624f7979Spbrook 		env->regwptr[UREG_I7] = ka->sa_restorer;
17986d5e216dSbellard 	else {
1799775b58d8Sbellard                 uint32_t val32;
1800459a4017Sbellard 
1801459a4017Sbellard 		env->regwptr[UREG_I7] = sf_addr +
1802459a4017Sbellard                         offsetof(struct target_signal_frame, insns) - 2 * 4;
18036d5e216dSbellard 
18046d5e216dSbellard 		/* mov __NR_sigreturn, %g1 */
1805775b58d8Sbellard                 val32 = 0x821020d8;
1806775b58d8Sbellard 		err |= __put_user(val32, &sf->insns[0]);
18076d5e216dSbellard 
18086d5e216dSbellard 		/* t 0x10 */
1809775b58d8Sbellard                 val32 = 0x91d02010;
1810775b58d8Sbellard 		err |= __put_user(val32, &sf->insns[1]);
18116d5e216dSbellard 		if (err)
18126d5e216dSbellard 			goto sigsegv;
18136d5e216dSbellard 
18146d5e216dSbellard 		/* Flush instruction space. */
18156d5e216dSbellard 		//flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
181680a9d035Sbellard                 //		tb_flush(env);
18176d5e216dSbellard 	}
1818459a4017Sbellard         unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
18196d5e216dSbellard 	return;
1820459a4017Sbellard #if 0
1821459a4017Sbellard sigill_and_return:
18226d5e216dSbellard 	force_sig(TARGET_SIGILL);
1823459a4017Sbellard #endif
18246d5e216dSbellard sigsegv:
1825e80cfcfcSbellard 	//fprintf(stderr, "force_sig\n");
1826459a4017Sbellard         unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
18276d5e216dSbellard 	force_sig(TARGET_SIGSEGV);
18286d5e216dSbellard }
18296d5e216dSbellard static inline int
183074ccb34eSbellard restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
18316d5e216dSbellard {
18326d5e216dSbellard         int err;
18336d5e216dSbellard #if 0
18346d5e216dSbellard #ifdef CONFIG_SMP
18356d5e216dSbellard         if (current->flags & PF_USEDFPU)
18366d5e216dSbellard                 regs->psr &= ~PSR_EF;
18376d5e216dSbellard #else
18386d5e216dSbellard         if (current == last_task_used_math) {
18396d5e216dSbellard                 last_task_used_math = 0;
18406d5e216dSbellard                 regs->psr &= ~PSR_EF;
18416d5e216dSbellard         }
18426d5e216dSbellard #endif
18436d5e216dSbellard         current->used_math = 1;
18446d5e216dSbellard         current->flags &= ~PF_USEDFPU;
18456d5e216dSbellard #endif
18466d5e216dSbellard #if 0
18476d5e216dSbellard         if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
18486d5e216dSbellard                 return -EFAULT;
18496d5e216dSbellard #endif
18506d5e216dSbellard 
1851fafffaefSbellard #if 0
1852fafffaefSbellard         /* XXX: incorrect */
18536d5e216dSbellard         err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
18546d5e216dSbellard 	                             (sizeof(unsigned long) * 32));
1855fafffaefSbellard #endif
18566d5e216dSbellard         err |= __get_user(env->fsr, &fpu->si_fsr);
18576d5e216dSbellard #if 0
18586d5e216dSbellard         err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
18596d5e216dSbellard         if (current->thread.fpqdepth != 0)
18606d5e216dSbellard                 err |= __copy_from_user(&current->thread.fpqueue[0],
18616d5e216dSbellard                                         &fpu->si_fpqueue[0],
18626d5e216dSbellard                                         ((sizeof(unsigned long) +
18636d5e216dSbellard                                         (sizeof(unsigned long *)))*16));
18646d5e216dSbellard #endif
18656d5e216dSbellard         return err;
18666d5e216dSbellard }
18676d5e216dSbellard 
18686d5e216dSbellard 
1869624f7979Spbrook static void setup_rt_frame(int sig, struct target_sigaction *ka,
18706d5e216dSbellard                            target_siginfo_t *info,
18716d5e216dSbellard 			   target_sigset_t *set, CPUState *env)
18726d5e216dSbellard {
18736d5e216dSbellard     fprintf(stderr, "setup_rt_frame: not implemented\n");
18746d5e216dSbellard }
18756d5e216dSbellard 
18766d5e216dSbellard long do_sigreturn(CPUState *env)
18776d5e216dSbellard {
1878f8b0aa25Sbellard         abi_ulong sf_addr;
18796d5e216dSbellard         struct target_signal_frame *sf;
1880e80cfcfcSbellard         uint32_t up_psr, pc, npc;
18816d5e216dSbellard         target_sigset_t set;
1882e80cfcfcSbellard         sigset_t host_set;
1883f8b0aa25Sbellard         abi_ulong fpu_save_addr;
1884e80cfcfcSbellard         int err, i;
18856d5e216dSbellard 
1886f8b0aa25Sbellard         sf_addr = env->regwptr[UREG_FP];
1887f8b0aa25Sbellard         if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
1888f8b0aa25Sbellard                 goto segv_and_exit;
188980a9d035Sbellard #if 0
1890e80cfcfcSbellard 	fprintf(stderr, "sigreturn\n");
1891e80cfcfcSbellard 	fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
189280a9d035Sbellard #endif
1893e80cfcfcSbellard 	//cpu_dump_state(env, stderr, fprintf, 0);
18946d5e216dSbellard 
18956d5e216dSbellard         /* 1. Make sure we are not getting garbage from the user */
18966d5e216dSbellard 
1897f8b0aa25Sbellard         if (sf_addr & 3)
18986d5e216dSbellard                 goto segv_and_exit;
18996d5e216dSbellard 
19006d5e216dSbellard         err = __get_user(pc,  &sf->info.si_regs.pc);
19016d5e216dSbellard         err |= __get_user(npc, &sf->info.si_regs.npc);
19026d5e216dSbellard 
19036d5e216dSbellard         if ((pc | npc) & 3)
19046d5e216dSbellard                 goto segv_and_exit;
19056d5e216dSbellard 
19066d5e216dSbellard         /* 2. Restore the state */
1907e80cfcfcSbellard         err |= __get_user(up_psr, &sf->info.si_regs.psr);
1908e80cfcfcSbellard 
19096d5e216dSbellard         /* User can only change condition codes and FPU enabling in %psr. */
1910a315a145Sbellard         env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
1911a315a145Sbellard                   | (env->psr & ~(PSR_ICC /* | PSR_EF */));
1912a315a145Sbellard 
1913a315a145Sbellard 	env->pc = pc;
1914a315a145Sbellard 	env->npc = npc;
1915e80cfcfcSbellard         err |= __get_user(env->y, &sf->info.si_regs.y);
1916a315a145Sbellard 	for (i=0; i < 8; i++) {
1917e80cfcfcSbellard 		err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
1918e80cfcfcSbellard 	}
1919a315a145Sbellard 	for (i=0; i < 8; i++) {
1920e80cfcfcSbellard 		err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
1921e80cfcfcSbellard 	}
19226d5e216dSbellard 
1923f8b0aa25Sbellard         err |= __get_user(fpu_save_addr, &sf->fpu_save);
19246d5e216dSbellard 
1925e80cfcfcSbellard         //if (fpu_save)
1926e80cfcfcSbellard         //        err |= restore_fpu_state(env, fpu_save);
19276d5e216dSbellard 
19286d5e216dSbellard         /* This is pretty much atomic, no amount locking would prevent
19296d5e216dSbellard          * the races which exist anyways.
19306d5e216dSbellard          */
19316d5e216dSbellard         err |= __get_user(set.sig[0], &sf->info.si_mask);
1932e80cfcfcSbellard         for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1933e80cfcfcSbellard             err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
1934e80cfcfcSbellard         }
1935e80cfcfcSbellard 
1936e80cfcfcSbellard         target_to_host_sigset_internal(&host_set, &set);
1937e80cfcfcSbellard         sigprocmask(SIG_SETMASK, &host_set, NULL);
19386d5e216dSbellard 
19396d5e216dSbellard         if (err)
19406d5e216dSbellard                 goto segv_and_exit;
1941f8b0aa25Sbellard         unlock_user_struct(sf, sf_addr, 0);
19426d5e216dSbellard         return env->regwptr[0];
19436d5e216dSbellard 
19446d5e216dSbellard segv_and_exit:
1945f8b0aa25Sbellard         unlock_user_struct(sf, sf_addr, 0);
19466d5e216dSbellard 	force_sig(TARGET_SIGSEGV);
19476d5e216dSbellard }
19486d5e216dSbellard 
19496d5e216dSbellard long do_rt_sigreturn(CPUState *env)
19506d5e216dSbellard {
19516d5e216dSbellard     fprintf(stderr, "do_rt_sigreturn: not implemented\n");
1952f8b0aa25Sbellard     return -TARGET_ENOSYS;
19536d5e216dSbellard }
19546d5e216dSbellard 
1955459a4017Sbellard #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
19565bfb56b2Sblueswir1 #define MC_TSTATE 0
19575bfb56b2Sblueswir1 #define MC_PC 1
19585bfb56b2Sblueswir1 #define MC_NPC 2
19595bfb56b2Sblueswir1 #define MC_Y 3
19605bfb56b2Sblueswir1 #define MC_G1 4
19615bfb56b2Sblueswir1 #define MC_G2 5
19625bfb56b2Sblueswir1 #define MC_G3 6
19635bfb56b2Sblueswir1 #define MC_G4 7
19645bfb56b2Sblueswir1 #define MC_G5 8
19655bfb56b2Sblueswir1 #define MC_G6 9
19665bfb56b2Sblueswir1 #define MC_G7 10
19675bfb56b2Sblueswir1 #define MC_O0 11
19685bfb56b2Sblueswir1 #define MC_O1 12
19695bfb56b2Sblueswir1 #define MC_O2 13
19705bfb56b2Sblueswir1 #define MC_O3 14
19715bfb56b2Sblueswir1 #define MC_O4 15
19725bfb56b2Sblueswir1 #define MC_O5 16
19735bfb56b2Sblueswir1 #define MC_O6 17
19745bfb56b2Sblueswir1 #define MC_O7 18
19755bfb56b2Sblueswir1 #define MC_NGREG 19
19765bfb56b2Sblueswir1 
1977992f48a0Sblueswir1 typedef abi_ulong target_mc_greg_t;
19785bfb56b2Sblueswir1 typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
19795bfb56b2Sblueswir1 
19805bfb56b2Sblueswir1 struct target_mc_fq {
1981992f48a0Sblueswir1     abi_ulong *mcfq_addr;
19825bfb56b2Sblueswir1     uint32_t mcfq_insn;
19835bfb56b2Sblueswir1 };
19845bfb56b2Sblueswir1 
19855bfb56b2Sblueswir1 struct target_mc_fpu {
19865bfb56b2Sblueswir1     union {
19875bfb56b2Sblueswir1         uint32_t sregs[32];
19885bfb56b2Sblueswir1         uint64_t dregs[32];
19895bfb56b2Sblueswir1         //uint128_t qregs[16];
19905bfb56b2Sblueswir1     } mcfpu_fregs;
1991992f48a0Sblueswir1     abi_ulong mcfpu_fsr;
1992992f48a0Sblueswir1     abi_ulong mcfpu_fprs;
1993992f48a0Sblueswir1     abi_ulong mcfpu_gsr;
19945bfb56b2Sblueswir1     struct target_mc_fq *mcfpu_fq;
19955bfb56b2Sblueswir1     unsigned char mcfpu_qcnt;
19965bfb56b2Sblueswir1     unsigned char mcfpu_qentsz;
19975bfb56b2Sblueswir1     unsigned char mcfpu_enab;
19985bfb56b2Sblueswir1 };
19995bfb56b2Sblueswir1 typedef struct target_mc_fpu target_mc_fpu_t;
20005bfb56b2Sblueswir1 
20015bfb56b2Sblueswir1 typedef struct {
20025bfb56b2Sblueswir1     target_mc_gregset_t mc_gregs;
20035bfb56b2Sblueswir1     target_mc_greg_t mc_fp;
20045bfb56b2Sblueswir1     target_mc_greg_t mc_i7;
20055bfb56b2Sblueswir1     target_mc_fpu_t mc_fpregs;
20065bfb56b2Sblueswir1 } target_mcontext_t;
20075bfb56b2Sblueswir1 
20085bfb56b2Sblueswir1 struct target_ucontext {
20095bfb56b2Sblueswir1     struct target_ucontext *uc_link;
2010992f48a0Sblueswir1     abi_ulong uc_flags;
20115bfb56b2Sblueswir1     target_sigset_t uc_sigmask;
20125bfb56b2Sblueswir1     target_mcontext_t uc_mcontext;
20135bfb56b2Sblueswir1 };
20145bfb56b2Sblueswir1 
20155bfb56b2Sblueswir1 /* A V9 register window */
20165bfb56b2Sblueswir1 struct target_reg_window {
2017992f48a0Sblueswir1     abi_ulong locals[8];
2018992f48a0Sblueswir1     abi_ulong ins[8];
20195bfb56b2Sblueswir1 };
20205bfb56b2Sblueswir1 
20215bfb56b2Sblueswir1 #define TARGET_STACK_BIAS 2047
20225bfb56b2Sblueswir1 
20235bfb56b2Sblueswir1 /* {set, get}context() needed for 64-bit SparcLinux userland. */
20245bfb56b2Sblueswir1 void sparc64_set_context(CPUSPARCState *env)
20255bfb56b2Sblueswir1 {
2026459a4017Sbellard     abi_ulong ucp_addr;
2027459a4017Sbellard     struct target_ucontext *ucp;
20285bfb56b2Sblueswir1     target_mc_gregset_t *grp;
2029992f48a0Sblueswir1     abi_ulong pc, npc, tstate;
2030459a4017Sbellard     abi_ulong fp, i7, w_addr;
20315bfb56b2Sblueswir1     unsigned char fenab;
20325bfb56b2Sblueswir1     int err;
20335bfb56b2Sblueswir1     unsigned int i;
20345bfb56b2Sblueswir1 
2035459a4017Sbellard     ucp_addr = env->regwptr[UREG_I0];
2036459a4017Sbellard     if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2037459a4017Sbellard         goto do_sigsegv;
20385bfb56b2Sblueswir1     grp  = &ucp->uc_mcontext.mc_gregs;
2039579a97f7Sbellard     err  = __get_user(pc, &((*grp)[MC_PC]));
2040579a97f7Sbellard     err |= __get_user(npc, &((*grp)[MC_NPC]));
20415bfb56b2Sblueswir1     if (err || ((pc | npc) & 3))
20425bfb56b2Sblueswir1         goto do_sigsegv;
20435bfb56b2Sblueswir1     if (env->regwptr[UREG_I1]) {
20445bfb56b2Sblueswir1         target_sigset_t target_set;
20455bfb56b2Sblueswir1         sigset_t set;
20465bfb56b2Sblueswir1 
20475bfb56b2Sblueswir1         if (TARGET_NSIG_WORDS == 1) {
2048579a97f7Sbellard             if (__get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0]))
20495bfb56b2Sblueswir1                 goto do_sigsegv;
20505bfb56b2Sblueswir1         } else {
2051459a4017Sbellard             abi_ulong *src, *dst;
2052459a4017Sbellard             src = ucp->uc_sigmask.sig;
2053459a4017Sbellard             dst = target_set.sig;
2054992f48a0Sblueswir1             for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
20555bfb56b2Sblueswir1                  i++, dst++, src++)
2056459a4017Sbellard                 err |= __get_user(*dst, src);
20575bfb56b2Sblueswir1             if (err)
20585bfb56b2Sblueswir1                 goto do_sigsegv;
20595bfb56b2Sblueswir1         }
20605bfb56b2Sblueswir1         target_to_host_sigset_internal(&set, &target_set);
20615bfb56b2Sblueswir1         sigprocmask(SIG_SETMASK, &set, NULL);
20625bfb56b2Sblueswir1     }
20635bfb56b2Sblueswir1     env->pc = pc;
20645bfb56b2Sblueswir1     env->npc = npc;
2065579a97f7Sbellard     err |= __get_user(env->y, &((*grp)[MC_Y]));
2066579a97f7Sbellard     err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
20675bfb56b2Sblueswir1     env->asi = (tstate >> 24) & 0xff;
20685bfb56b2Sblueswir1     PUT_CCR(env, tstate >> 32);
20695bfb56b2Sblueswir1     PUT_CWP64(env, tstate & 0x1f);
2070579a97f7Sbellard     err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2071579a97f7Sbellard     err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2072579a97f7Sbellard     err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2073579a97f7Sbellard     err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2074579a97f7Sbellard     err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2075579a97f7Sbellard     err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2076579a97f7Sbellard     err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2077579a97f7Sbellard     err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2078579a97f7Sbellard     err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2079579a97f7Sbellard     err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2080579a97f7Sbellard     err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2081579a97f7Sbellard     err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2082579a97f7Sbellard     err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2083579a97f7Sbellard     err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2084579a97f7Sbellard     err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
20855bfb56b2Sblueswir1 
2086579a97f7Sbellard     err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp));
2087579a97f7Sbellard     err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7));
20885bfb56b2Sblueswir1 
2089459a4017Sbellard     w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2090459a4017Sbellard     if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2091459a4017Sbellard                  abi_ulong) != 0)
2092459a4017Sbellard         goto do_sigsegv;
2093459a4017Sbellard     if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2094459a4017Sbellard                  abi_ulong) != 0)
2095459a4017Sbellard         goto do_sigsegv;
2096579a97f7Sbellard     err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
2097579a97f7Sbellard     err |= __get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
2098459a4017Sbellard     {
2099459a4017Sbellard         uint32_t *src, *dst;
2100459a4017Sbellard         src = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2101459a4017Sbellard         dst = env->fpr;
2102459a4017Sbellard         /* XXX: check that the CPU storage is the same as user context */
21035bfb56b2Sblueswir1         for (i = 0; i < 64; i++, dst++, src++)
2104459a4017Sbellard             err |= __get_user(*dst, src);
2105459a4017Sbellard     }
2106579a97f7Sbellard     err |= __get_user(env->fsr,
21075bfb56b2Sblueswir1                       &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
2108579a97f7Sbellard     err |= __get_user(env->gsr,
21095bfb56b2Sblueswir1                       &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
21105bfb56b2Sblueswir1     if (err)
21115bfb56b2Sblueswir1         goto do_sigsegv;
2112459a4017Sbellard     unlock_user_struct(ucp, ucp_addr, 0);
21135bfb56b2Sblueswir1     return;
21145bfb56b2Sblueswir1  do_sigsegv:
2115459a4017Sbellard     unlock_user_struct(ucp, ucp_addr, 0);
21165bfb56b2Sblueswir1     force_sig(SIGSEGV);
21175bfb56b2Sblueswir1 }
21185bfb56b2Sblueswir1 
21195bfb56b2Sblueswir1 void sparc64_get_context(CPUSPARCState *env)
21205bfb56b2Sblueswir1 {
2121459a4017Sbellard     abi_ulong ucp_addr;
2122459a4017Sbellard     struct target_ucontext *ucp;
21235bfb56b2Sblueswir1     target_mc_gregset_t *grp;
21245bfb56b2Sblueswir1     target_mcontext_t *mcp;
2125459a4017Sbellard     abi_ulong fp, i7, w_addr;
21265bfb56b2Sblueswir1     int err;
21275bfb56b2Sblueswir1     unsigned int i;
21285bfb56b2Sblueswir1     target_sigset_t target_set;
21295bfb56b2Sblueswir1     sigset_t set;
21305bfb56b2Sblueswir1 
2131459a4017Sbellard     ucp_addr = env->regwptr[UREG_I0];
2132459a4017Sbellard     if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2133459a4017Sbellard         goto do_sigsegv;
2134459a4017Sbellard 
21355bfb56b2Sblueswir1     mcp = &ucp->uc_mcontext;
21365bfb56b2Sblueswir1     grp = &mcp->mc_gregs;
21375bfb56b2Sblueswir1 
21385bfb56b2Sblueswir1     /* Skip over the trap instruction, first. */
21395bfb56b2Sblueswir1     env->pc = env->npc;
21405bfb56b2Sblueswir1     env->npc += 4;
21415bfb56b2Sblueswir1 
21425bfb56b2Sblueswir1     err = 0;
21435bfb56b2Sblueswir1 
21445bfb56b2Sblueswir1     sigprocmask(0, NULL, &set);
21455bfb56b2Sblueswir1     host_to_target_sigset_internal(&target_set, &set);
2146459a4017Sbellard     if (TARGET_NSIG_WORDS == 1) {
2147579a97f7Sbellard         err |= __put_user(target_set.sig[0],
2148992f48a0Sblueswir1                           (abi_ulong *)&ucp->uc_sigmask);
2149459a4017Sbellard     } else {
2150459a4017Sbellard         abi_ulong *src, *dst;
2151459a4017Sbellard         src = target_set.sig;
2152459a4017Sbellard         dst = ucp->uc_sigmask.sig;
2153992f48a0Sblueswir1         for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
21545bfb56b2Sblueswir1              i++, dst++, src++)
2155459a4017Sbellard             err |= __put_user(*src, dst);
21565bfb56b2Sblueswir1         if (err)
21575bfb56b2Sblueswir1             goto do_sigsegv;
21585bfb56b2Sblueswir1     }
21595bfb56b2Sblueswir1 
2160459a4017Sbellard     /* XXX: tstate must be saved properly */
2161459a4017Sbellard     //    err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2162579a97f7Sbellard     err |= __put_user(env->pc, &((*grp)[MC_PC]));
2163579a97f7Sbellard     err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2164579a97f7Sbellard     err |= __put_user(env->y, &((*grp)[MC_Y]));
2165579a97f7Sbellard     err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2166579a97f7Sbellard     err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2167579a97f7Sbellard     err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2168579a97f7Sbellard     err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2169579a97f7Sbellard     err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2170579a97f7Sbellard     err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2171579a97f7Sbellard     err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2172579a97f7Sbellard     err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2173579a97f7Sbellard     err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2174579a97f7Sbellard     err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2175579a97f7Sbellard     err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2176579a97f7Sbellard     err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2177579a97f7Sbellard     err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2178579a97f7Sbellard     err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2179579a97f7Sbellard     err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
21805bfb56b2Sblueswir1 
2181459a4017Sbellard     w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2182459a4017Sbellard     fp = i7 = 0;
2183459a4017Sbellard     if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2184459a4017Sbellard                  abi_ulong) != 0)
2185459a4017Sbellard         goto do_sigsegv;
2186459a4017Sbellard     if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2187459a4017Sbellard                  abi_ulong) != 0)
2188459a4017Sbellard         goto do_sigsegv;
2189579a97f7Sbellard     err |= __put_user(fp, &(mcp->mc_fp));
2190579a97f7Sbellard     err |= __put_user(i7, &(mcp->mc_i7));
21915bfb56b2Sblueswir1 
2192459a4017Sbellard     {
2193459a4017Sbellard         uint32_t *src, *dst;
2194459a4017Sbellard         src = env->fpr;
2195459a4017Sbellard         dst = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2196459a4017Sbellard         /* XXX: check that the CPU storage is the same as user context */
21975bfb56b2Sblueswir1         for (i = 0; i < 64; i++, dst++, src++)
2198459a4017Sbellard             err |= __put_user(*src, dst);
2199459a4017Sbellard     }
2200579a97f7Sbellard     err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2201579a97f7Sbellard     err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2202579a97f7Sbellard     err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
22035bfb56b2Sblueswir1 
22045bfb56b2Sblueswir1     if (err)
22055bfb56b2Sblueswir1         goto do_sigsegv;
2206459a4017Sbellard     unlock_user_struct(ucp, ucp_addr, 1);
22075bfb56b2Sblueswir1     return;
22085bfb56b2Sblueswir1  do_sigsegv:
2209459a4017Sbellard     unlock_user_struct(ucp, ucp_addr, 1);
22105bfb56b2Sblueswir1     force_sig(SIGSEGV);
22115bfb56b2Sblueswir1 }
22125bfb56b2Sblueswir1 #endif
2213d26bc211Sths #elif defined(TARGET_ABI_MIPSN64)
2214540635baSths 
2215540635baSths # warning signal handling not implemented
2216540635baSths 
2217624f7979Spbrook static void setup_frame(int sig, struct target_sigaction *ka,
2218540635baSths 			target_sigset_t *set, CPUState *env)
2219540635baSths {
2220540635baSths     fprintf(stderr, "setup_frame: not implemented\n");
2221540635baSths }
2222540635baSths 
2223624f7979Spbrook static void setup_rt_frame(int sig, struct target_sigaction *ka,
2224540635baSths                            target_siginfo_t *info,
2225540635baSths 			   target_sigset_t *set, CPUState *env)
2226540635baSths {
2227540635baSths     fprintf(stderr, "setup_rt_frame: not implemented\n");
2228540635baSths }
2229540635baSths 
2230540635baSths long do_sigreturn(CPUState *env)
2231540635baSths {
2232540635baSths     fprintf(stderr, "do_sigreturn: not implemented\n");
2233f8b0aa25Sbellard     return -TARGET_ENOSYS;
2234540635baSths }
2235540635baSths 
2236540635baSths long do_rt_sigreturn(CPUState *env)
2237540635baSths {
2238540635baSths     fprintf(stderr, "do_rt_sigreturn: not implemented\n");
2239f8b0aa25Sbellard     return -TARGET_ENOSYS;
2240540635baSths }
2241540635baSths 
2242d26bc211Sths #elif defined(TARGET_ABI_MIPSN32)
2243540635baSths 
2244540635baSths # warning signal handling not implemented
2245540635baSths 
2246624f7979Spbrook static void setup_frame(int sig, struct target_sigaction *ka,
2247540635baSths 			target_sigset_t *set, CPUState *env)
2248540635baSths {
2249540635baSths     fprintf(stderr, "setup_frame: not implemented\n");
2250540635baSths }
2251540635baSths 
2252624f7979Spbrook static void setup_rt_frame(int sig, struct target_sigaction *ka,
2253540635baSths                            target_siginfo_t *info,
2254540635baSths 			   target_sigset_t *set, CPUState *env)
2255540635baSths {
2256540635baSths     fprintf(stderr, "setup_rt_frame: not implemented\n");
2257540635baSths }
2258540635baSths 
2259540635baSths long do_sigreturn(CPUState *env)
2260540635baSths {
2261540635baSths     fprintf(stderr, "do_sigreturn: not implemented\n");
2262f8b0aa25Sbellard     return -TARGET_ENOSYS;
2263540635baSths }
2264540635baSths 
2265540635baSths long do_rt_sigreturn(CPUState *env)
2266540635baSths {
2267540635baSths     fprintf(stderr, "do_rt_sigreturn: not implemented\n");
2268f8b0aa25Sbellard     return -TARGET_ENOSYS;
2269540635baSths }
2270540635baSths 
2271d26bc211Sths #elif defined(TARGET_ABI_MIPSO32)
2272106ec879Sbellard 
2273106ec879Sbellard struct target_sigcontext {
2274106ec879Sbellard     uint32_t   sc_regmask;     /* Unused */
2275106ec879Sbellard     uint32_t   sc_status;
2276106ec879Sbellard     uint64_t   sc_pc;
2277106ec879Sbellard     uint64_t   sc_regs[32];
2278106ec879Sbellard     uint64_t   sc_fpregs[32];
2279106ec879Sbellard     uint32_t   sc_ownedfp;     /* Unused */
2280106ec879Sbellard     uint32_t   sc_fpc_csr;
2281106ec879Sbellard     uint32_t   sc_fpc_eir;     /* Unused */
2282106ec879Sbellard     uint32_t   sc_used_math;
2283106ec879Sbellard     uint32_t   sc_dsp;         /* dsp status, was sc_ssflags */
2284106ec879Sbellard     uint64_t   sc_mdhi;
2285106ec879Sbellard     uint64_t   sc_mdlo;
2286106ec879Sbellard     target_ulong   sc_hi1;         /* Was sc_cause */
2287106ec879Sbellard     target_ulong   sc_lo1;         /* Was sc_badvaddr */
2288106ec879Sbellard     target_ulong   sc_hi2;         /* Was sc_sigset[4] */
2289106ec879Sbellard     target_ulong   sc_lo2;
2290106ec879Sbellard     target_ulong   sc_hi3;
2291106ec879Sbellard     target_ulong   sc_lo3;
2292106ec879Sbellard };
2293106ec879Sbellard 
2294106ec879Sbellard struct sigframe {
2295106ec879Sbellard     uint32_t sf_ass[4];			/* argument save space for o32 */
2296106ec879Sbellard     uint32_t sf_code[2];			/* signal trampoline */
2297106ec879Sbellard     struct target_sigcontext sf_sc;
2298106ec879Sbellard     target_sigset_t sf_mask;
2299106ec879Sbellard };
2300106ec879Sbellard 
2301106ec879Sbellard /* Install trampoline to jump back from signal handler */
2302106ec879Sbellard static inline int install_sigtramp(unsigned int *tramp,   unsigned int syscall)
2303106ec879Sbellard {
2304106ec879Sbellard     int err;
2305106ec879Sbellard 
2306106ec879Sbellard     /*
2307106ec879Sbellard     * Set up the return code ...
2308106ec879Sbellard     *
2309106ec879Sbellard     *         li      v0, __NR__foo_sigreturn
2310106ec879Sbellard     *         syscall
2311106ec879Sbellard     */
2312106ec879Sbellard 
2313106ec879Sbellard     err = __put_user(0x24020000 + syscall, tramp + 0);
2314106ec879Sbellard     err |= __put_user(0x0000000c          , tramp + 1);
2315106ec879Sbellard     /* flush_cache_sigtramp((unsigned long) tramp); */
2316106ec879Sbellard     return err;
2317106ec879Sbellard }
2318106ec879Sbellard 
2319106ec879Sbellard static inline int
2320106ec879Sbellard setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2321106ec879Sbellard {
2322106ec879Sbellard     int err = 0;
2323106ec879Sbellard 
2324b5dc7732Sths     err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
2325106ec879Sbellard 
2326106ec879Sbellard #define save_gp_reg(i) do {   						\
2327b5dc7732Sths         err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);	\
2328106ec879Sbellard     } while(0)
2329106ec879Sbellard     __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
2330106ec879Sbellard     save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
2331106ec879Sbellard     save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
2332106ec879Sbellard     save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
2333106ec879Sbellard     save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
2334106ec879Sbellard     save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
2335106ec879Sbellard     save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
2336106ec879Sbellard     save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
2337106ec879Sbellard     save_gp_reg(31);
2338106ec879Sbellard #undef save_gp_reg
2339106ec879Sbellard 
2340b5dc7732Sths     err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2341b5dc7732Sths     err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
2342106ec879Sbellard 
2343106ec879Sbellard     /* Not used yet, but might be useful if we ever have DSP suppport */
2344106ec879Sbellard #if 0
2345106ec879Sbellard     if (cpu_has_dsp) {
2346106ec879Sbellard 	err |= __put_user(mfhi1(), &sc->sc_hi1);
2347106ec879Sbellard 	err |= __put_user(mflo1(), &sc->sc_lo1);
2348106ec879Sbellard 	err |= __put_user(mfhi2(), &sc->sc_hi2);
2349106ec879Sbellard 	err |= __put_user(mflo2(), &sc->sc_lo2);
2350106ec879Sbellard 	err |= __put_user(mfhi3(), &sc->sc_hi3);
2351106ec879Sbellard 	err |= __put_user(mflo3(), &sc->sc_lo3);
2352106ec879Sbellard 	err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2353106ec879Sbellard     }
2354106ec879Sbellard     /* same with 64 bit */
2355106ec879Sbellard #ifdef CONFIG_64BIT
2356106ec879Sbellard     err |= __put_user(regs->hi, &sc->sc_hi[0]);
2357106ec879Sbellard     err |= __put_user(regs->lo, &sc->sc_lo[0]);
2358106ec879Sbellard     if (cpu_has_dsp) {
2359106ec879Sbellard 	err |= __put_user(mfhi1(), &sc->sc_hi[1]);
2360106ec879Sbellard 	err |= __put_user(mflo1(), &sc->sc_lo[1]);
2361106ec879Sbellard 	err |= __put_user(mfhi2(), &sc->sc_hi[2]);
2362106ec879Sbellard 	err |= __put_user(mflo2(), &sc->sc_lo[2]);
2363106ec879Sbellard 	err |= __put_user(mfhi3(), &sc->sc_hi[3]);
2364106ec879Sbellard 	err |= __put_user(mflo3(), &sc->sc_lo[3]);
2365106ec879Sbellard 	err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2366106ec879Sbellard     }
2367106ec879Sbellard #endif
2368106ec879Sbellard #endif
2369106ec879Sbellard 
2370106ec879Sbellard #if 0
2371106ec879Sbellard     err |= __put_user(!!used_math(), &sc->sc_used_math);
2372106ec879Sbellard 
2373106ec879Sbellard     if (!used_math())
2374106ec879Sbellard 	goto out;
2375106ec879Sbellard 
2376106ec879Sbellard     /*
2377106ec879Sbellard     * Save FPU state to signal context.  Signal handler will "inherit"
2378106ec879Sbellard     * current FPU state.
2379106ec879Sbellard     */
2380106ec879Sbellard     preempt_disable();
2381106ec879Sbellard 
2382106ec879Sbellard     if (!is_fpu_owner()) {
2383106ec879Sbellard 	own_fpu();
2384106ec879Sbellard 	restore_fp(current);
2385106ec879Sbellard     }
2386106ec879Sbellard     err |= save_fp_context(sc);
2387106ec879Sbellard 
2388106ec879Sbellard     preempt_enable();
2389106ec879Sbellard     out:
2390106ec879Sbellard #endif
2391106ec879Sbellard     return err;
2392106ec879Sbellard }
2393106ec879Sbellard 
2394106ec879Sbellard static inline int
2395106ec879Sbellard restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2396106ec879Sbellard {
2397106ec879Sbellard     int err = 0;
2398106ec879Sbellard 
2399106ec879Sbellard     err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2400106ec879Sbellard 
2401b5dc7732Sths     err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2402b5dc7732Sths     err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
2403106ec879Sbellard 
2404106ec879Sbellard #define restore_gp_reg(i) do {   							\
2405b5dc7732Sths         err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);		\
2406106ec879Sbellard     } while(0)
2407106ec879Sbellard     restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
2408106ec879Sbellard     restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
2409106ec879Sbellard     restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
2410106ec879Sbellard     restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
2411106ec879Sbellard     restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
2412106ec879Sbellard     restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
2413106ec879Sbellard     restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
2414106ec879Sbellard     restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
2415106ec879Sbellard     restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
2416106ec879Sbellard     restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
2417106ec879Sbellard     restore_gp_reg(31);
2418106ec879Sbellard #undef restore_gp_reg
2419106ec879Sbellard 
2420106ec879Sbellard #if 0
2421106ec879Sbellard     if (cpu_has_dsp) {
2422106ec879Sbellard 	err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
2423106ec879Sbellard 	err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
2424106ec879Sbellard 	err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
2425106ec879Sbellard 	err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
2426106ec879Sbellard 	err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
2427106ec879Sbellard 	err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2428106ec879Sbellard 	err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2429106ec879Sbellard     }
2430106ec879Sbellard #ifdef CONFIG_64BIT
2431106ec879Sbellard     err |= __get_user(regs->hi, &sc->sc_hi[0]);
2432106ec879Sbellard     err |= __get_user(regs->lo, &sc->sc_lo[0]);
2433106ec879Sbellard     if (cpu_has_dsp) {
2434106ec879Sbellard 	err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
2435106ec879Sbellard 	err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
2436106ec879Sbellard 	err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
2437106ec879Sbellard 	err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
2438106ec879Sbellard 	err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
2439106ec879Sbellard 	err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
2440106ec879Sbellard 	err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2441106ec879Sbellard     }
2442106ec879Sbellard #endif
2443106ec879Sbellard 
2444106ec879Sbellard     err |= __get_user(used_math, &sc->sc_used_math);
2445106ec879Sbellard     conditional_used_math(used_math);
2446106ec879Sbellard 
2447106ec879Sbellard     preempt_disable();
2448106ec879Sbellard 
2449106ec879Sbellard     if (used_math()) {
2450106ec879Sbellard 	/* restore fpu context if we have used it before */
2451106ec879Sbellard 	own_fpu();
2452106ec879Sbellard 	err |= restore_fp_context(sc);
2453106ec879Sbellard     } else {
2454106ec879Sbellard 	/* signal handler may have used FPU.  Give it up. */
2455106ec879Sbellard 	lose_fpu();
2456106ec879Sbellard     }
2457106ec879Sbellard 
2458106ec879Sbellard     preempt_enable();
2459106ec879Sbellard #endif
2460106ec879Sbellard     return err;
2461106ec879Sbellard }
2462106ec879Sbellard /*
2463106ec879Sbellard  * Determine which stack to use..
2464106ec879Sbellard  */
2465579a97f7Sbellard static inline abi_ulong
2466624f7979Spbrook get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
2467106ec879Sbellard {
2468106ec879Sbellard     unsigned long sp;
2469106ec879Sbellard 
2470106ec879Sbellard     /* Default to using normal stack */
2471b5dc7732Sths     sp = regs->active_tc.gpr[29];
2472106ec879Sbellard 
2473106ec879Sbellard     /*
2474106ec879Sbellard      * FPU emulator may have it's own trampoline active just
2475106ec879Sbellard      * above the user stack, 16-bytes before the next lowest
2476106ec879Sbellard      * 16 byte boundary.  Try to avoid trashing it.
2477106ec879Sbellard      */
2478106ec879Sbellard     sp -= 32;
2479106ec879Sbellard 
2480106ec879Sbellard     /* This is the X/Open sanctioned signal stack switching.  */
2481624f7979Spbrook     if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
2482a04e134aSths         sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2483a04e134aSths     }
2484106ec879Sbellard 
2485579a97f7Sbellard     return (sp - frame_size) & ~7;
2486106ec879Sbellard }
2487106ec879Sbellard 
2488579a97f7Sbellard /* compare linux/arch/mips/kernel/signal.c:setup_frame() */
2489624f7979Spbrook static void setup_frame(int sig, struct target_sigaction * ka,
2490106ec879Sbellard                         target_sigset_t *set, CPUState *regs)
2491106ec879Sbellard {
2492106ec879Sbellard     struct sigframe *frame;
2493579a97f7Sbellard     abi_ulong frame_addr;
2494106ec879Sbellard     int i;
2495106ec879Sbellard 
2496579a97f7Sbellard     frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2497579a97f7Sbellard     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2498106ec879Sbellard 	goto give_sigsegv;
2499106ec879Sbellard 
2500106ec879Sbellard     install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2501106ec879Sbellard 
2502106ec879Sbellard     if(setup_sigcontext(regs, &frame->sf_sc))
2503106ec879Sbellard 	goto give_sigsegv;
2504106ec879Sbellard 
2505106ec879Sbellard     for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2506106ec879Sbellard 	if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2507106ec879Sbellard 	    goto give_sigsegv;
2508106ec879Sbellard     }
2509106ec879Sbellard 
2510106ec879Sbellard     /*
2511106ec879Sbellard     * Arguments to signal handler:
2512106ec879Sbellard     *
2513106ec879Sbellard     *   a0 = signal number
2514106ec879Sbellard     *   a1 = 0 (should be cause)
2515106ec879Sbellard     *   a2 = pointer to struct sigcontext
2516106ec879Sbellard     *
2517106ec879Sbellard     * $25 and PC point to the signal handler, $29 points to the
2518106ec879Sbellard     * struct sigframe.
2519106ec879Sbellard     */
2520b5dc7732Sths     regs->active_tc.gpr[ 4] = sig;
2521b5dc7732Sths     regs->active_tc.gpr[ 5] = 0;
2522b5dc7732Sths     regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2523b5dc7732Sths     regs->active_tc.gpr[29] = frame_addr;
2524b5dc7732Sths     regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
2525106ec879Sbellard     /* The original kernel code sets CP0_EPC to the handler
2526106ec879Sbellard     * since it returns to userland using eret
2527106ec879Sbellard     * we cannot do this here, and we must set PC directly */
2528b5dc7732Sths     regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
2529579a97f7Sbellard     unlock_user_struct(frame, frame_addr, 1);
2530106ec879Sbellard     return;
2531106ec879Sbellard 
2532106ec879Sbellard give_sigsegv:
2533579a97f7Sbellard     unlock_user_struct(frame, frame_addr, 1);
2534106ec879Sbellard     force_sig(TARGET_SIGSEGV/*, current*/);
2535106ec879Sbellard     return;
2536106ec879Sbellard }
2537106ec879Sbellard 
2538106ec879Sbellard long do_sigreturn(CPUState *regs)
2539106ec879Sbellard {
2540106ec879Sbellard     struct sigframe *frame;
2541579a97f7Sbellard     abi_ulong frame_addr;
2542106ec879Sbellard     sigset_t blocked;
2543106ec879Sbellard     target_sigset_t target_set;
2544106ec879Sbellard     int i;
2545106ec879Sbellard 
2546106ec879Sbellard #if defined(DEBUG_SIGNAL)
2547106ec879Sbellard     fprintf(stderr, "do_sigreturn\n");
2548106ec879Sbellard #endif
2549b5dc7732Sths     frame_addr = regs->active_tc.gpr[29];
2550579a97f7Sbellard     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2551106ec879Sbellard    	goto badframe;
2552106ec879Sbellard 
2553106ec879Sbellard     for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2554106ec879Sbellard    	if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2555106ec879Sbellard 	    goto badframe;
2556106ec879Sbellard     }
2557106ec879Sbellard 
2558106ec879Sbellard     target_to_host_sigset_internal(&blocked, &target_set);
2559106ec879Sbellard     sigprocmask(SIG_SETMASK, &blocked, NULL);
2560106ec879Sbellard 
2561106ec879Sbellard     if (restore_sigcontext(regs, &frame->sf_sc))
2562106ec879Sbellard    	goto badframe;
2563106ec879Sbellard 
2564106ec879Sbellard #if 0
2565106ec879Sbellard     /*
2566106ec879Sbellard      * Don't let your children do this ...
2567106ec879Sbellard      */
2568106ec879Sbellard     __asm__ __volatile__(
2569106ec879Sbellard    	"move\t$29, %0\n\t"
2570106ec879Sbellard    	"j\tsyscall_exit"
2571106ec879Sbellard    	:/* no outputs */
2572106ec879Sbellard    	:"r" (&regs));
2573106ec879Sbellard     /* Unreached */
2574106ec879Sbellard #endif
2575106ec879Sbellard 
2576b5dc7732Sths     regs->active_tc.PC = regs->CP0_EPC;
2577106ec879Sbellard     /* I am not sure this is right, but it seems to work
2578106ec879Sbellard     * maybe a problem with nested signals ? */
2579106ec879Sbellard     regs->CP0_EPC = 0;
2580106ec879Sbellard     return 0;
2581106ec879Sbellard 
2582106ec879Sbellard badframe:
2583106ec879Sbellard     force_sig(TARGET_SIGSEGV/*, current*/);
2584106ec879Sbellard     return 0;
2585106ec879Sbellard }
2586106ec879Sbellard 
2587624f7979Spbrook static void setup_rt_frame(int sig, struct target_sigaction *ka,
2588106ec879Sbellard                            target_siginfo_t *info,
2589106ec879Sbellard 			   target_sigset_t *set, CPUState *env)
2590106ec879Sbellard {
2591106ec879Sbellard     fprintf(stderr, "setup_rt_frame: not implemented\n");
2592106ec879Sbellard }
2593106ec879Sbellard 
2594106ec879Sbellard long do_rt_sigreturn(CPUState *env)
2595106ec879Sbellard {
2596106ec879Sbellard     fprintf(stderr, "do_rt_sigreturn: not implemented\n");
2597f8b0aa25Sbellard     return -TARGET_ENOSYS;
2598106ec879Sbellard }
25996d5e216dSbellard 
2600c3b5bc8aSths #elif defined(TARGET_SH4)
2601c3b5bc8aSths 
2602c3b5bc8aSths /*
2603c3b5bc8aSths  * code and data structures from linux kernel:
2604c3b5bc8aSths  * include/asm-sh/sigcontext.h
2605c3b5bc8aSths  * arch/sh/kernel/signal.c
2606c3b5bc8aSths  */
2607c3b5bc8aSths 
2608c3b5bc8aSths struct target_sigcontext {
2609c3b5bc8aSths     target_ulong  oldmask;
2610c3b5bc8aSths 
2611c3b5bc8aSths     /* CPU registers */
2612c3b5bc8aSths     target_ulong  sc_gregs[16];
2613c3b5bc8aSths     target_ulong  sc_pc;
2614c3b5bc8aSths     target_ulong  sc_pr;
2615c3b5bc8aSths     target_ulong  sc_sr;
2616c3b5bc8aSths     target_ulong  sc_gbr;
2617c3b5bc8aSths     target_ulong  sc_mach;
2618c3b5bc8aSths     target_ulong  sc_macl;
2619c3b5bc8aSths 
2620c3b5bc8aSths     /* FPU registers */
2621c3b5bc8aSths     target_ulong  sc_fpregs[16];
2622c3b5bc8aSths     target_ulong  sc_xfpregs[16];
2623c3b5bc8aSths     unsigned int sc_fpscr;
2624c3b5bc8aSths     unsigned int sc_fpul;
2625c3b5bc8aSths     unsigned int sc_ownedfp;
2626c3b5bc8aSths };
2627c3b5bc8aSths 
2628c3b5bc8aSths struct target_sigframe
2629c3b5bc8aSths {
2630c3b5bc8aSths     struct target_sigcontext sc;
2631c3b5bc8aSths     target_ulong extramask[TARGET_NSIG_WORDS-1];
2632c3b5bc8aSths     uint16_t retcode[3];
2633c3b5bc8aSths };
2634c3b5bc8aSths 
2635c3b5bc8aSths 
2636c3b5bc8aSths struct target_ucontext {
2637c3b5bc8aSths     target_ulong uc_flags;
2638c3b5bc8aSths     struct target_ucontext *uc_link;
2639c3b5bc8aSths     target_stack_t uc_stack;
2640c3b5bc8aSths     struct target_sigcontext uc_mcontext;
2641c3b5bc8aSths     target_sigset_t uc_sigmask;	/* mask last for extensibility */
2642c3b5bc8aSths };
2643c3b5bc8aSths 
2644c3b5bc8aSths struct target_rt_sigframe
2645c3b5bc8aSths {
2646c3b5bc8aSths     struct target_siginfo info;
2647c3b5bc8aSths     struct target_ucontext uc;
2648c3b5bc8aSths     uint16_t retcode[3];
2649c3b5bc8aSths };
2650c3b5bc8aSths 
2651c3b5bc8aSths 
2652c3b5bc8aSths #define MOVW(n)  (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
2653c3b5bc8aSths #define TRAP_NOARG 0xc310         /* Syscall w/no args (NR in R3) SH3/4 */
2654c3b5bc8aSths 
2655624f7979Spbrook static abi_ulong get_sigframe(struct target_sigaction *ka,
2656c3b5bc8aSths                          unsigned long sp, size_t frame_size)
2657c3b5bc8aSths {
2658624f7979Spbrook     if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
2659c3b5bc8aSths         sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2660c3b5bc8aSths     }
2661c3b5bc8aSths 
2662c3b5bc8aSths     return (sp - frame_size) & -8ul;
2663c3b5bc8aSths }
2664c3b5bc8aSths 
2665c3b5bc8aSths static int setup_sigcontext(struct target_sigcontext *sc,
2666c3b5bc8aSths 			    CPUState *regs, unsigned long mask)
2667c3b5bc8aSths {
2668c3b5bc8aSths     int err = 0;
2669c3b5bc8aSths 
2670c3b5bc8aSths #define COPY(x)         err |= __put_user(regs->x, &sc->sc_##x)
2671c3b5bc8aSths     COPY(gregs[0]); COPY(gregs[1]);
2672c3b5bc8aSths     COPY(gregs[2]); COPY(gregs[3]);
2673c3b5bc8aSths     COPY(gregs[4]); COPY(gregs[5]);
2674c3b5bc8aSths     COPY(gregs[6]); COPY(gregs[7]);
2675c3b5bc8aSths     COPY(gregs[8]); COPY(gregs[9]);
2676c3b5bc8aSths     COPY(gregs[10]); COPY(gregs[11]);
2677c3b5bc8aSths     COPY(gregs[12]); COPY(gregs[13]);
2678c3b5bc8aSths     COPY(gregs[14]); COPY(gregs[15]);
2679c3b5bc8aSths     COPY(gbr); COPY(mach);
2680c3b5bc8aSths     COPY(macl); COPY(pr);
2681c3b5bc8aSths     COPY(sr); COPY(pc);
2682c3b5bc8aSths #undef COPY
2683c3b5bc8aSths 
2684c3b5bc8aSths     /* todo: save FPU registers here */
2685c3b5bc8aSths 
2686c3b5bc8aSths     /* non-iBCS2 extensions.. */
2687c3b5bc8aSths     err |= __put_user(mask, &sc->oldmask);
2688c3b5bc8aSths 
2689c3b5bc8aSths     return err;
2690c3b5bc8aSths }
2691c3b5bc8aSths 
2692c3b5bc8aSths static int restore_sigcontext(struct CPUState *regs,
2693c3b5bc8aSths 			      struct target_sigcontext *sc)
2694c3b5bc8aSths {
2695c3b5bc8aSths     unsigned int err = 0;
2696c3b5bc8aSths 
2697c3b5bc8aSths #define COPY(x)         err |= __get_user(regs->x, &sc->sc_##x)
2698c3b5bc8aSths     COPY(gregs[1]);
2699c3b5bc8aSths     COPY(gregs[2]); COPY(gregs[3]);
2700c3b5bc8aSths     COPY(gregs[4]); COPY(gregs[5]);
2701c3b5bc8aSths     COPY(gregs[6]); COPY(gregs[7]);
2702c3b5bc8aSths     COPY(gregs[8]); COPY(gregs[9]);
2703c3b5bc8aSths     COPY(gregs[10]); COPY(gregs[11]);
2704c3b5bc8aSths     COPY(gregs[12]); COPY(gregs[13]);
2705c3b5bc8aSths     COPY(gregs[14]); COPY(gregs[15]);
2706c3b5bc8aSths     COPY(gbr); COPY(mach);
2707c3b5bc8aSths     COPY(macl); COPY(pr);
2708c3b5bc8aSths     COPY(sr); COPY(pc);
2709c3b5bc8aSths #undef COPY
2710c3b5bc8aSths 
2711c3b5bc8aSths     /* todo: restore FPU registers here */
2712c3b5bc8aSths 
2713c3b5bc8aSths     regs->tra = -1;         /* disable syscall checks */
2714c3b5bc8aSths     return err;
2715c3b5bc8aSths }
2716c3b5bc8aSths 
2717624f7979Spbrook static void setup_frame(int sig, struct target_sigaction *ka,
2718c3b5bc8aSths 			target_sigset_t *set, CPUState *regs)
2719c3b5bc8aSths {
2720c3b5bc8aSths     struct target_sigframe *frame;
2721c3b5bc8aSths     abi_ulong frame_addr;
2722c3b5bc8aSths     int i;
2723c3b5bc8aSths     int err = 0;
2724c3b5bc8aSths     int signal;
2725c3b5bc8aSths 
2726c3b5bc8aSths     frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2727c3b5bc8aSths     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2728c3b5bc8aSths 	goto give_sigsegv;
2729c3b5bc8aSths 
2730c3b5bc8aSths     signal = current_exec_domain_sig(sig);
2731c3b5bc8aSths 
2732c3b5bc8aSths     err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
2733c3b5bc8aSths 
2734c3b5bc8aSths     for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2735c3b5bc8aSths         err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
2736c3b5bc8aSths     }
2737c3b5bc8aSths 
2738c3b5bc8aSths     /* Set up to return from userspace.  If provided, use a stub
2739c3b5bc8aSths        already in userspace.  */
2740624f7979Spbrook     if (ka->sa_flags & TARGET_SA_RESTORER) {
2741624f7979Spbrook         regs->pr = (unsigned long) ka->sa_restorer;
2742c3b5bc8aSths     } else {
2743c3b5bc8aSths         /* Generate return code (system call to sigreturn) */
2744c3b5bc8aSths         err |= __put_user(MOVW(2), &frame->retcode[0]);
2745c3b5bc8aSths         err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2746c3b5bc8aSths         err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
2747c3b5bc8aSths         regs->pr = (unsigned long) frame->retcode;
2748c3b5bc8aSths     }
2749c3b5bc8aSths 
2750c3b5bc8aSths     if (err)
2751c3b5bc8aSths         goto give_sigsegv;
2752c3b5bc8aSths 
2753c3b5bc8aSths     /* Set up registers for signal handler */
2754c3b5bc8aSths     regs->gregs[15] = (unsigned long) frame;
2755c3b5bc8aSths     regs->gregs[4] = signal; /* Arg for signal handler */
2756c3b5bc8aSths     regs->gregs[5] = 0;
2757c3b5bc8aSths     regs->gregs[6] = (unsigned long) &frame->sc;
2758624f7979Spbrook     regs->pc = (unsigned long) ka->_sa_handler;
2759c3b5bc8aSths 
2760c3b5bc8aSths     unlock_user_struct(frame, frame_addr, 1);
2761c3b5bc8aSths     return;
2762c3b5bc8aSths 
2763c3b5bc8aSths give_sigsegv:
2764c3b5bc8aSths     unlock_user_struct(frame, frame_addr, 1);
2765c3b5bc8aSths     force_sig(SIGSEGV);
2766c3b5bc8aSths }
2767c3b5bc8aSths 
2768624f7979Spbrook static void setup_rt_frame(int sig, struct target_sigaction *ka,
2769c3b5bc8aSths                            target_siginfo_t *info,
2770c3b5bc8aSths 			   target_sigset_t *set, CPUState *regs)
2771c3b5bc8aSths {
2772c3b5bc8aSths     struct target_rt_sigframe *frame;
2773c3b5bc8aSths     abi_ulong frame_addr;
2774c3b5bc8aSths     int i;
2775c3b5bc8aSths     int err = 0;
2776c3b5bc8aSths     int signal;
2777c3b5bc8aSths 
2778c3b5bc8aSths     frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2779c3b5bc8aSths     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2780c3b5bc8aSths 	goto give_sigsegv;
2781c3b5bc8aSths 
2782c3b5bc8aSths     signal = current_exec_domain_sig(sig);
2783c3b5bc8aSths 
2784c3b5bc8aSths     err |= copy_siginfo_to_user(&frame->info, info);
2785c3b5bc8aSths 
2786c3b5bc8aSths     /* Create the ucontext.  */
2787c3b5bc8aSths     err |= __put_user(0, &frame->uc.uc_flags);
2788c3b5bc8aSths     err |= __put_user(0, (unsigned long *)&frame->uc.uc_link);
2789526ccb7aSbalrog     err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
2790c3b5bc8aSths 		      &frame->uc.uc_stack.ss_sp);
2791c3b5bc8aSths     err |= __put_user(sas_ss_flags(regs->gregs[15]),
2792c3b5bc8aSths 		      &frame->uc.uc_stack.ss_flags);
2793c3b5bc8aSths     err |= __put_user(target_sigaltstack_used.ss_size,
2794c3b5bc8aSths 		      &frame->uc.uc_stack.ss_size);
2795c3b5bc8aSths     err |= setup_sigcontext(&frame->uc.uc_mcontext,
2796c3b5bc8aSths 			    regs, set->sig[0]);
2797c3b5bc8aSths     for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2798c3b5bc8aSths         err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]);
2799c3b5bc8aSths     }
2800c3b5bc8aSths 
2801c3b5bc8aSths     /* Set up to return from userspace.  If provided, use a stub
2802c3b5bc8aSths        already in userspace.  */
2803624f7979Spbrook     if (ka->sa_flags & TARGET_SA_RESTORER) {
2804624f7979Spbrook         regs->pr = (unsigned long) ka->sa_restorer;
2805c3b5bc8aSths     } else {
2806c3b5bc8aSths         /* Generate return code (system call to sigreturn) */
2807c3b5bc8aSths         err |= __put_user(MOVW(2), &frame->retcode[0]);
2808c3b5bc8aSths         err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2809c3b5bc8aSths         err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
2810c3b5bc8aSths         regs->pr = (unsigned long) frame->retcode;
2811c3b5bc8aSths     }
2812c3b5bc8aSths 
2813c3b5bc8aSths     if (err)
2814c3b5bc8aSths         goto give_sigsegv;
2815c3b5bc8aSths 
2816c3b5bc8aSths     /* Set up registers for signal handler */
2817c3b5bc8aSths     regs->gregs[15] = (unsigned long) frame;
2818c3b5bc8aSths     regs->gregs[4] = signal; /* Arg for signal handler */
2819c3b5bc8aSths     regs->gregs[5] = (unsigned long) &frame->info;
2820c3b5bc8aSths     regs->gregs[6] = (unsigned long) &frame->uc;
2821624f7979Spbrook     regs->pc = (unsigned long) ka->_sa_handler;
2822c3b5bc8aSths 
2823c3b5bc8aSths     unlock_user_struct(frame, frame_addr, 1);
2824c3b5bc8aSths     return;
2825c3b5bc8aSths 
2826c3b5bc8aSths give_sigsegv:
2827c3b5bc8aSths     unlock_user_struct(frame, frame_addr, 1);
2828c3b5bc8aSths     force_sig(SIGSEGV);
2829c3b5bc8aSths }
2830c3b5bc8aSths 
2831c3b5bc8aSths long do_sigreturn(CPUState *regs)
2832c3b5bc8aSths {
2833c3b5bc8aSths     struct target_sigframe *frame;
2834c3b5bc8aSths     abi_ulong frame_addr;
2835c3b5bc8aSths     sigset_t blocked;
2836c3b5bc8aSths     target_sigset_t target_set;
2837c3b5bc8aSths     int i;
2838c3b5bc8aSths     int err = 0;
2839c3b5bc8aSths 
2840c3b5bc8aSths #if defined(DEBUG_SIGNAL)
2841c3b5bc8aSths     fprintf(stderr, "do_sigreturn\n");
2842c3b5bc8aSths #endif
2843c3b5bc8aSths     frame_addr = regs->gregs[15];
2844c3b5bc8aSths     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2845c3b5bc8aSths    	goto badframe;
2846c3b5bc8aSths 
2847c3b5bc8aSths     err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
2848c3b5bc8aSths     for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2849c3b5bc8aSths         err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
2850c3b5bc8aSths     }
2851c3b5bc8aSths 
2852c3b5bc8aSths     if (err)
2853c3b5bc8aSths         goto badframe;
2854c3b5bc8aSths 
2855c3b5bc8aSths     target_to_host_sigset_internal(&blocked, &target_set);
2856c3b5bc8aSths     sigprocmask(SIG_SETMASK, &blocked, NULL);
2857c3b5bc8aSths 
2858c3b5bc8aSths     if (restore_sigcontext(regs, &frame->sc))
2859c3b5bc8aSths         goto badframe;
2860c3b5bc8aSths 
2861c3b5bc8aSths     unlock_user_struct(frame, frame_addr, 0);
2862c3b5bc8aSths     return regs->gregs[0];
2863c3b5bc8aSths 
2864c3b5bc8aSths badframe:
2865c3b5bc8aSths     unlock_user_struct(frame, frame_addr, 0);
2866c3b5bc8aSths     force_sig(TARGET_SIGSEGV);
2867c3b5bc8aSths     return 0;
2868c3b5bc8aSths }
2869c3b5bc8aSths 
2870c3b5bc8aSths long do_rt_sigreturn(CPUState *regs)
2871c3b5bc8aSths {
2872c3b5bc8aSths     struct target_rt_sigframe *frame;
2873c3b5bc8aSths     abi_ulong frame_addr;
2874c3b5bc8aSths     sigset_t blocked;
2875c3b5bc8aSths 
2876c3b5bc8aSths #if defined(DEBUG_SIGNAL)
2877c3b5bc8aSths     fprintf(stderr, "do_rt_sigreturn\n");
2878c3b5bc8aSths #endif
2879c3b5bc8aSths     frame_addr = regs->gregs[15];
2880c3b5bc8aSths     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2881c3b5bc8aSths    	goto badframe;
2882c3b5bc8aSths 
2883c3b5bc8aSths     target_to_host_sigset(&blocked, &frame->uc.uc_sigmask);
2884c3b5bc8aSths     sigprocmask(SIG_SETMASK, &blocked, NULL);
2885c3b5bc8aSths 
2886c3b5bc8aSths     if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
2887c3b5bc8aSths         goto badframe;
2888c3b5bc8aSths 
2889c3b5bc8aSths     if (do_sigaltstack(frame_addr +
2890c3b5bc8aSths 		       offsetof(struct target_rt_sigframe, uc.uc_stack),
2891c3b5bc8aSths 		       0, get_sp_from_cpustate(regs)) == -EFAULT)
2892c3b5bc8aSths         goto badframe;
2893c3b5bc8aSths 
2894c3b5bc8aSths     unlock_user_struct(frame, frame_addr, 0);
2895c3b5bc8aSths     return regs->gregs[0];
2896c3b5bc8aSths 
2897c3b5bc8aSths badframe:
2898c3b5bc8aSths     unlock_user_struct(frame, frame_addr, 0);
2899c3b5bc8aSths     force_sig(TARGET_SIGSEGV);
2900c3b5bc8aSths     return 0;
2901c3b5bc8aSths }
2902b6d3abdaSedgar_igl #elif defined(TARGET_CRIS)
2903b6d3abdaSedgar_igl 
2904b6d3abdaSedgar_igl struct target_sigcontext {
2905b6d3abdaSedgar_igl         struct target_pt_regs regs;  /* needs to be first */
2906b6d3abdaSedgar_igl         uint32_t oldmask;
2907b6d3abdaSedgar_igl         uint32_t usp;    /* usp before stacking this gunk on it */
2908b6d3abdaSedgar_igl };
2909b6d3abdaSedgar_igl 
2910b6d3abdaSedgar_igl /* Signal frames. */
2911b6d3abdaSedgar_igl struct target_signal_frame {
2912b6d3abdaSedgar_igl         struct target_sigcontext sc;
2913b6d3abdaSedgar_igl         uint32_t extramask[TARGET_NSIG_WORDS - 1];
2914b6d3abdaSedgar_igl         uint8_t retcode[8];       /* Trampoline code. */
2915b6d3abdaSedgar_igl };
2916b6d3abdaSedgar_igl 
2917b6d3abdaSedgar_igl struct rt_signal_frame {
2918b6d3abdaSedgar_igl         struct siginfo *pinfo;
2919b6d3abdaSedgar_igl         void *puc;
2920b6d3abdaSedgar_igl         struct siginfo info;
2921b6d3abdaSedgar_igl         struct ucontext uc;
2922b6d3abdaSedgar_igl         uint8_t retcode[8];       /* Trampoline code. */
2923b6d3abdaSedgar_igl };
2924b6d3abdaSedgar_igl 
2925b6d3abdaSedgar_igl static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
2926b6d3abdaSedgar_igl {
29279664d928Sedgar_igl 	__put_user(env->regs[0], &sc->regs.r0);
29289664d928Sedgar_igl 	__put_user(env->regs[1], &sc->regs.r1);
29299664d928Sedgar_igl 	__put_user(env->regs[2], &sc->regs.r2);
29309664d928Sedgar_igl 	__put_user(env->regs[3], &sc->regs.r3);
29319664d928Sedgar_igl 	__put_user(env->regs[4], &sc->regs.r4);
29329664d928Sedgar_igl 	__put_user(env->regs[5], &sc->regs.r5);
29339664d928Sedgar_igl 	__put_user(env->regs[6], &sc->regs.r6);
29349664d928Sedgar_igl 	__put_user(env->regs[7], &sc->regs.r7);
29359664d928Sedgar_igl 	__put_user(env->regs[8], &sc->regs.r8);
29369664d928Sedgar_igl 	__put_user(env->regs[9], &sc->regs.r9);
29379664d928Sedgar_igl 	__put_user(env->regs[10], &sc->regs.r10);
29389664d928Sedgar_igl 	__put_user(env->regs[11], &sc->regs.r11);
29399664d928Sedgar_igl 	__put_user(env->regs[12], &sc->regs.r12);
29409664d928Sedgar_igl 	__put_user(env->regs[13], &sc->regs.r13);
29419664d928Sedgar_igl 	__put_user(env->regs[14], &sc->usp);
29429664d928Sedgar_igl 	__put_user(env->regs[15], &sc->regs.acr);
29439664d928Sedgar_igl 	__put_user(env->pregs[PR_MOF], &sc->regs.mof);
29449664d928Sedgar_igl 	__put_user(env->pregs[PR_SRP], &sc->regs.srp);
29459664d928Sedgar_igl 	__put_user(env->pc, &sc->regs.erp);
2946b6d3abdaSedgar_igl }
29479664d928Sedgar_igl 
2948b6d3abdaSedgar_igl static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
2949b6d3abdaSedgar_igl {
29509664d928Sedgar_igl 	__get_user(env->regs[0], &sc->regs.r0);
29519664d928Sedgar_igl 	__get_user(env->regs[1], &sc->regs.r1);
29529664d928Sedgar_igl 	__get_user(env->regs[2], &sc->regs.r2);
29539664d928Sedgar_igl 	__get_user(env->regs[3], &sc->regs.r3);
29549664d928Sedgar_igl 	__get_user(env->regs[4], &sc->regs.r4);
29559664d928Sedgar_igl 	__get_user(env->regs[5], &sc->regs.r5);
29569664d928Sedgar_igl 	__get_user(env->regs[6], &sc->regs.r6);
29579664d928Sedgar_igl 	__get_user(env->regs[7], &sc->regs.r7);
29589664d928Sedgar_igl 	__get_user(env->regs[8], &sc->regs.r8);
29599664d928Sedgar_igl 	__get_user(env->regs[9], &sc->regs.r9);
29609664d928Sedgar_igl 	__get_user(env->regs[10], &sc->regs.r10);
29619664d928Sedgar_igl 	__get_user(env->regs[11], &sc->regs.r11);
29629664d928Sedgar_igl 	__get_user(env->regs[12], &sc->regs.r12);
29639664d928Sedgar_igl 	__get_user(env->regs[13], &sc->regs.r13);
29649664d928Sedgar_igl 	__get_user(env->regs[14], &sc->usp);
29659664d928Sedgar_igl 	__get_user(env->regs[15], &sc->regs.acr);
29669664d928Sedgar_igl 	__get_user(env->pregs[PR_MOF], &sc->regs.mof);
29679664d928Sedgar_igl 	__get_user(env->pregs[PR_SRP], &sc->regs.srp);
29689664d928Sedgar_igl 	__get_user(env->pc, &sc->regs.erp);
2969b6d3abdaSedgar_igl }
2970b6d3abdaSedgar_igl 
29719664d928Sedgar_igl static abi_ulong get_sigframe(CPUState *env, int framesize)
2972b6d3abdaSedgar_igl {
29739664d928Sedgar_igl 	abi_ulong sp;
2974b6d3abdaSedgar_igl 	/* Align the stack downwards to 4.  */
29759664d928Sedgar_igl 	sp = (env->regs[R_SP] & ~3);
29769664d928Sedgar_igl 	return sp - framesize;
2977b6d3abdaSedgar_igl }
2978b6d3abdaSedgar_igl 
2979624f7979Spbrook static void setup_frame(int sig, struct target_sigaction *ka,
2980b6d3abdaSedgar_igl 			target_sigset_t *set, CPUState *env)
2981b6d3abdaSedgar_igl {
2982b6d3abdaSedgar_igl 	struct target_signal_frame *frame;
29839664d928Sedgar_igl 	abi_ulong frame_addr;
2984b6d3abdaSedgar_igl 	int err = 0;
2985b6d3abdaSedgar_igl 	int i;
2986b6d3abdaSedgar_igl 
29879664d928Sedgar_igl 	frame_addr = get_sigframe(env, sizeof *frame);
29889664d928Sedgar_igl 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2989b6d3abdaSedgar_igl 		goto badframe;
2990b6d3abdaSedgar_igl 
2991b6d3abdaSedgar_igl 	/*
2992b6d3abdaSedgar_igl 	 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
2993b6d3abdaSedgar_igl 	 * use this trampoline anymore but it sets it up for GDB.
2994b6d3abdaSedgar_igl 	 * In QEMU, using the trampoline simplifies things a bit so we use it.
2995b6d3abdaSedgar_igl 	 *
2996b6d3abdaSedgar_igl 	 * This is movu.w __NR_sigreturn, r9; break 13;
2997b6d3abdaSedgar_igl 	 */
2998b6d3abdaSedgar_igl 	err |= __put_user(0x9c5f, frame->retcode+0);
2999b6d3abdaSedgar_igl 	err |= __put_user(TARGET_NR_sigreturn,
3000b6d3abdaSedgar_igl 			  frame->retcode+2);
3001b6d3abdaSedgar_igl 	err |= __put_user(0xe93d, frame->retcode+4);
3002b6d3abdaSedgar_igl 
3003b6d3abdaSedgar_igl 	/* Save the mask.  */
3004b6d3abdaSedgar_igl 	err |= __put_user(set->sig[0], &frame->sc.oldmask);
3005b6d3abdaSedgar_igl 	if (err)
3006b6d3abdaSedgar_igl 		goto badframe;
3007b6d3abdaSedgar_igl 
3008b6d3abdaSedgar_igl 	for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3009b6d3abdaSedgar_igl 		if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3010b6d3abdaSedgar_igl 			goto badframe;
3011b6d3abdaSedgar_igl 	}
3012b6d3abdaSedgar_igl 
3013b6d3abdaSedgar_igl 	setup_sigcontext(&frame->sc, env);
3014b6d3abdaSedgar_igl 
3015b6d3abdaSedgar_igl 	/* Move the stack and setup the arguments for the handler.  */
3016526ccb7aSbalrog 	env->regs[R_SP] = (uint32_t) (unsigned long) frame;
3017b6d3abdaSedgar_igl 	env->regs[10] = sig;
3018624f7979Spbrook 	env->pc = (unsigned long) ka->_sa_handler;
3019b6d3abdaSedgar_igl 	/* Link SRP so the guest returns through the trampoline.  */
3020526ccb7aSbalrog 	env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
3021b6d3abdaSedgar_igl 
30229664d928Sedgar_igl 	unlock_user_struct(frame, frame_addr, 1);
3023b6d3abdaSedgar_igl 	return;
3024b6d3abdaSedgar_igl   badframe:
30259664d928Sedgar_igl 	unlock_user_struct(frame, frame_addr, 1);
3026b6d3abdaSedgar_igl 	force_sig(TARGET_SIGSEGV);
3027b6d3abdaSedgar_igl }
3028b6d3abdaSedgar_igl 
3029624f7979Spbrook static void setup_rt_frame(int sig, struct target_sigaction *ka,
3030b6d3abdaSedgar_igl                            target_siginfo_t *info,
3031b6d3abdaSedgar_igl 			   target_sigset_t *set, CPUState *env)
3032b6d3abdaSedgar_igl {
3033b6d3abdaSedgar_igl     fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3034b6d3abdaSedgar_igl }
3035b6d3abdaSedgar_igl 
3036b6d3abdaSedgar_igl long do_sigreturn(CPUState *env)
3037b6d3abdaSedgar_igl {
3038b6d3abdaSedgar_igl 	struct target_signal_frame *frame;
30399664d928Sedgar_igl 	abi_ulong frame_addr;
3040b6d3abdaSedgar_igl 	target_sigset_t target_set;
3041b6d3abdaSedgar_igl 	sigset_t set;
3042b6d3abdaSedgar_igl 	int i;
3043b6d3abdaSedgar_igl 
30449664d928Sedgar_igl 	frame_addr = env->regs[R_SP];
3045b6d3abdaSedgar_igl 	/* Make sure the guest isn't playing games.  */
30469664d928Sedgar_igl 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3047b6d3abdaSedgar_igl 		goto badframe;
3048b6d3abdaSedgar_igl 
3049b6d3abdaSedgar_igl 	/* Restore blocked signals */
3050b6d3abdaSedgar_igl 	if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3051b6d3abdaSedgar_igl 		goto badframe;
3052b6d3abdaSedgar_igl 	for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3053b6d3abdaSedgar_igl 		if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3054b6d3abdaSedgar_igl 			goto badframe;
3055b6d3abdaSedgar_igl 	}
3056b6d3abdaSedgar_igl 	target_to_host_sigset_internal(&set, &target_set);
3057b6d3abdaSedgar_igl 	sigprocmask(SIG_SETMASK, &set, NULL);
3058b6d3abdaSedgar_igl 
3059b6d3abdaSedgar_igl 	restore_sigcontext(&frame->sc, env);
30609664d928Sedgar_igl 	unlock_user_struct(frame, frame_addr, 0);
3061b6d3abdaSedgar_igl 	return env->regs[10];
3062b6d3abdaSedgar_igl   badframe:
30639664d928Sedgar_igl 	unlock_user_struct(frame, frame_addr, 0);
3064b6d3abdaSedgar_igl 	force_sig(TARGET_SIGSEGV);
3065b6d3abdaSedgar_igl }
3066b6d3abdaSedgar_igl 
3067b6d3abdaSedgar_igl long do_rt_sigreturn(CPUState *env)
3068b6d3abdaSedgar_igl {
3069b6d3abdaSedgar_igl     fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3070b6d3abdaSedgar_igl     return -TARGET_ENOSYS;
3071b6d3abdaSedgar_igl }
3072c3b5bc8aSths 
3073b346ff46Sbellard #else
3074b346ff46Sbellard 
3075624f7979Spbrook static void setup_frame(int sig, struct target_sigaction *ka,
3076b346ff46Sbellard 			target_sigset_t *set, CPUState *env)
3077b346ff46Sbellard {
3078b346ff46Sbellard     fprintf(stderr, "setup_frame: not implemented\n");
3079b346ff46Sbellard }
3080b346ff46Sbellard 
3081624f7979Spbrook static void setup_rt_frame(int sig, struct target_sigaction *ka,
3082b346ff46Sbellard                            target_siginfo_t *info,
3083b346ff46Sbellard 			   target_sigset_t *set, CPUState *env)
3084b346ff46Sbellard {
3085b346ff46Sbellard     fprintf(stderr, "setup_rt_frame: not implemented\n");
3086b346ff46Sbellard }
3087b346ff46Sbellard 
3088b346ff46Sbellard long do_sigreturn(CPUState *env)
3089b346ff46Sbellard {
3090b346ff46Sbellard     fprintf(stderr, "do_sigreturn: not implemented\n");
3091f8b0aa25Sbellard     return -TARGET_ENOSYS;
3092b346ff46Sbellard }
3093b346ff46Sbellard 
3094b346ff46Sbellard long do_rt_sigreturn(CPUState *env)
3095b346ff46Sbellard {
3096b346ff46Sbellard     fprintf(stderr, "do_rt_sigreturn: not implemented\n");
3097f8b0aa25Sbellard     return -TARGET_ENOSYS;
3098b346ff46Sbellard }
3099b346ff46Sbellard 
310066fb9763Sbellard #endif
310166fb9763Sbellard 
3102624f7979Spbrook void process_pending_signals(CPUState *cpu_env)
310366fb9763Sbellard {
310466fb9763Sbellard     int sig;
3105992f48a0Sblueswir1     abi_ulong handler;
31069de5e440Sbellard     sigset_t set, old_set;
31079de5e440Sbellard     target_sigset_t target_old_set;
3108624f7979Spbrook     struct emulated_sigtable *k;
3109624f7979Spbrook     struct target_sigaction *sa;
311066fb9763Sbellard     struct sigqueue *q;
3111624f7979Spbrook     TaskState *ts = cpu_env->opaque;
311231e31b8aSbellard 
3113624f7979Spbrook     if (!ts->signal_pending)
311431e31b8aSbellard         return;
311531e31b8aSbellard 
3116624f7979Spbrook     /* FIXME: This is not threadsafe.  */
3117624f7979Spbrook     k = ts->sigtab;
311866fb9763Sbellard     for(sig = 1; sig <= TARGET_NSIG; sig++) {
311966fb9763Sbellard         if (k->pending)
312031e31b8aSbellard             goto handle_signal;
312166fb9763Sbellard         k++;
312231e31b8aSbellard     }
312331e31b8aSbellard     /* if no signal is pending, just return */
3124624f7979Spbrook     ts->signal_pending = 0;
312531e31b8aSbellard     return;
312666fb9763Sbellard 
312731e31b8aSbellard  handle_signal:
312866fb9763Sbellard #ifdef DEBUG_SIGNAL
3129bc8a22ccSbellard     fprintf(stderr, "qemu: process signal %d\n", sig);
313066fb9763Sbellard #endif
313166fb9763Sbellard     /* dequeue signal */
313266fb9763Sbellard     q = k->first;
313366fb9763Sbellard     k->first = q->next;
313466fb9763Sbellard     if (!k->first)
313566fb9763Sbellard         k->pending = 0;
31361fddef4bSbellard 
31371fddef4bSbellard     sig = gdb_handlesig (cpu_env, sig);
31381fddef4bSbellard     if (!sig) {
3139*ca587a8eSaurel32         sa = NULL;
3140*ca587a8eSaurel32         handler = TARGET_SIG_IGN;
3141*ca587a8eSaurel32     } else {
3142624f7979Spbrook         sa = &sigact_table[sig - 1];
3143624f7979Spbrook         handler = sa->_sa_handler;
3144*ca587a8eSaurel32     }
3145*ca587a8eSaurel32 
314666fb9763Sbellard     if (handler == TARGET_SIG_DFL) {
3147*ca587a8eSaurel32         /* default handler : ignore some signal. The other are job control or fatal */
3148*ca587a8eSaurel32         if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
3149*ca587a8eSaurel32             kill(getpid(),SIGSTOP);
3150*ca587a8eSaurel32         } else if (sig != TARGET_SIGCHLD &&
315166fb9763Sbellard                    sig != TARGET_SIGURG &&
3152*ca587a8eSaurel32                    sig != TARGET_SIGWINCH &&
3153*ca587a8eSaurel32                    sig != TARGET_SIGCONT) {
315466fb9763Sbellard             force_sig(sig);
315566fb9763Sbellard         }
315666fb9763Sbellard     } else if (handler == TARGET_SIG_IGN) {
315766fb9763Sbellard         /* ignore sig */
315866fb9763Sbellard     } else if (handler == TARGET_SIG_ERR) {
315966fb9763Sbellard         force_sig(sig);
316066fb9763Sbellard     } else {
31619de5e440Sbellard         /* compute the blocked signals during the handler execution */
3162624f7979Spbrook         target_to_host_sigset(&set, &sa->sa_mask);
31639de5e440Sbellard         /* SA_NODEFER indicates that the current signal should not be
31649de5e440Sbellard            blocked during the handler */
3165624f7979Spbrook         if (!(sa->sa_flags & TARGET_SA_NODEFER))
31669de5e440Sbellard             sigaddset(&set, target_to_host_signal(sig));
31679de5e440Sbellard 
31689de5e440Sbellard         /* block signals in the handler using Linux */
31699de5e440Sbellard         sigprocmask(SIG_BLOCK, &set, &old_set);
31709de5e440Sbellard         /* save the previous blocked signal state to restore it at the
31719de5e440Sbellard            end of the signal execution (see do_sigreturn) */
31729231944dSbellard         host_to_target_sigset_internal(&target_old_set, &old_set);
31739de5e440Sbellard 
3174bc8a22ccSbellard         /* if the CPU is in VM86 mode, we restore the 32 bit values */
317584409ddbSj_mayer #if defined(TARGET_I386) && !defined(TARGET_X86_64)
3176bc8a22ccSbellard         {
3177bc8a22ccSbellard             CPUX86State *env = cpu_env;
3178bc8a22ccSbellard             if (env->eflags & VM_MASK)
3179bc8a22ccSbellard                 save_v86_state(env);
3180bc8a22ccSbellard         }
3181bc8a22ccSbellard #endif
31829de5e440Sbellard         /* prepare the stack frame of the virtual CPU */
3183624f7979Spbrook         if (sa->sa_flags & TARGET_SA_SIGINFO)
3184624f7979Spbrook             setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
318566fb9763Sbellard         else
3186624f7979Spbrook             setup_frame(sig, sa, &target_old_set, cpu_env);
3187624f7979Spbrook 	if (sa->sa_flags & TARGET_SA_RESETHAND)
3188624f7979Spbrook             sa->_sa_handler = TARGET_SIG_DFL;
318966fb9763Sbellard     }
319066fb9763Sbellard     if (q != &k->info)
3191624f7979Spbrook         free_sigqueue(cpu_env, q);
319231e31b8aSbellard }
3193