xref: /qemu/linux-user/signal.c (revision 773b93ee)
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 
290d330196Sbellard #ifdef __ia64__
300d330196Sbellard #undef uc_mcontext
310d330196Sbellard #undef uc_sigmask
320d330196Sbellard #undef uc_stack
330d330196Sbellard #undef uc_link
340d330196Sbellard #endif
350d330196Sbellard 
363ef693a0Sbellard #include "qemu.h"
3766fb9763Sbellard 
3866fb9763Sbellard //#define DEBUG_SIGNAL
3966fb9763Sbellard 
4066fb9763Sbellard #define MAX_SIGQUEUE_SIZE 1024
4166fb9763Sbellard 
4266fb9763Sbellard struct sigqueue {
4366fb9763Sbellard     struct sigqueue *next;
449de5e440Sbellard     target_siginfo_t info;
4566fb9763Sbellard };
4631e31b8aSbellard 
4731e31b8aSbellard struct emulated_sigaction {
4831e31b8aSbellard     struct target_sigaction sa;
4966fb9763Sbellard     int pending; /* true if signal is pending */
5066fb9763Sbellard     struct sigqueue *first;
5166fb9763Sbellard     struct sigqueue info; /* in order to always have memory for the
5266fb9763Sbellard                              first signal, we put it here */
5331e31b8aSbellard };
5431e31b8aSbellard 
5566fb9763Sbellard static struct emulated_sigaction sigact_table[TARGET_NSIG];
5666fb9763Sbellard static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
5766fb9763Sbellard static struct sigqueue *first_free; /* first free siginfo queue entry */
5866fb9763Sbellard static int signal_pending; /* non zero if a signal may be pending */
5931e31b8aSbellard 
6066fb9763Sbellard static void host_signal_handler(int host_signum, siginfo_t *info,
6166fb9763Sbellard                                 void *puc);
6266fb9763Sbellard 
639e5f5284Sbellard static uint8_t host_to_target_signal_table[65] = {
649e5f5284Sbellard     [SIGHUP] = TARGET_SIGHUP,
659e5f5284Sbellard     [SIGINT] = TARGET_SIGINT,
669e5f5284Sbellard     [SIGQUIT] = TARGET_SIGQUIT,
679e5f5284Sbellard     [SIGILL] = TARGET_SIGILL,
689e5f5284Sbellard     [SIGTRAP] = TARGET_SIGTRAP,
699e5f5284Sbellard     [SIGABRT] = TARGET_SIGABRT,
7001e3b763Sbellard /*    [SIGIOT] = TARGET_SIGIOT,*/
719e5f5284Sbellard     [SIGBUS] = TARGET_SIGBUS,
729e5f5284Sbellard     [SIGFPE] = TARGET_SIGFPE,
739e5f5284Sbellard     [SIGKILL] = TARGET_SIGKILL,
749e5f5284Sbellard     [SIGUSR1] = TARGET_SIGUSR1,
759e5f5284Sbellard     [SIGSEGV] = TARGET_SIGSEGV,
769e5f5284Sbellard     [SIGUSR2] = TARGET_SIGUSR2,
779e5f5284Sbellard     [SIGPIPE] = TARGET_SIGPIPE,
789e5f5284Sbellard     [SIGALRM] = TARGET_SIGALRM,
799e5f5284Sbellard     [SIGTERM] = TARGET_SIGTERM,
809e5f5284Sbellard #ifdef SIGSTKFLT
819e5f5284Sbellard     [SIGSTKFLT] = TARGET_SIGSTKFLT,
829e5f5284Sbellard #endif
839e5f5284Sbellard     [SIGCHLD] = TARGET_SIGCHLD,
849e5f5284Sbellard     [SIGCONT] = TARGET_SIGCONT,
859e5f5284Sbellard     [SIGSTOP] = TARGET_SIGSTOP,
869e5f5284Sbellard     [SIGTSTP] = TARGET_SIGTSTP,
879e5f5284Sbellard     [SIGTTIN] = TARGET_SIGTTIN,
889e5f5284Sbellard     [SIGTTOU] = TARGET_SIGTTOU,
899e5f5284Sbellard     [SIGURG] = TARGET_SIGURG,
909e5f5284Sbellard     [SIGXCPU] = TARGET_SIGXCPU,
919e5f5284Sbellard     [SIGXFSZ] = TARGET_SIGXFSZ,
929e5f5284Sbellard     [SIGVTALRM] = TARGET_SIGVTALRM,
939e5f5284Sbellard     [SIGPROF] = TARGET_SIGPROF,
949e5f5284Sbellard     [SIGWINCH] = TARGET_SIGWINCH,
959e5f5284Sbellard     [SIGIO] = TARGET_SIGIO,
969e5f5284Sbellard     [SIGPWR] = TARGET_SIGPWR,
979e5f5284Sbellard     [SIGSYS] = TARGET_SIGSYS,
989e5f5284Sbellard     /* next signals stay the same */
999e5f5284Sbellard };
1009e5f5284Sbellard static uint8_t target_to_host_signal_table[65];
1019e5f5284Sbellard 
10231e31b8aSbellard static inline int host_to_target_signal(int sig)
10331e31b8aSbellard {
1049e5f5284Sbellard     return host_to_target_signal_table[sig];
10531e31b8aSbellard }
10631e31b8aSbellard 
10731e31b8aSbellard static inline int target_to_host_signal(int sig)
10831e31b8aSbellard {
1099e5f5284Sbellard     return target_to_host_signal_table[sig];
11031e31b8aSbellard }
11131e31b8aSbellard 
1129e5f5284Sbellard void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
11366fb9763Sbellard {
11466fb9763Sbellard     int i;
1159e5f5284Sbellard     unsigned long sigmask;
1169e5f5284Sbellard     uint32_t target_sigmask;
1179e5f5284Sbellard 
1189e5f5284Sbellard     sigmask = ((unsigned long *)s)[0];
1199e5f5284Sbellard     target_sigmask = 0;
1209e5f5284Sbellard     for(i = 0; i < 32; i++) {
1219e5f5284Sbellard         if (sigmask & (1 << i))
1229e5f5284Sbellard             target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);
1239e5f5284Sbellard     }
1249e5f5284Sbellard #if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
1259e5f5284Sbellard     d->sig[0] = tswapl(target_sigmask);
1269e5f5284Sbellard     for(i = 1;i < TARGET_NSIG_WORDS; i++) {
12766fb9763Sbellard         d->sig[i] = tswapl(((unsigned long *)s)[i]);
12866fb9763Sbellard     }
1299e5f5284Sbellard #elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
1309e5f5284Sbellard     d->sig[0] = tswapl(target_sigmask);
1319e5f5284Sbellard     d->sig[1] = tswapl(sigmask >> 32);
1329e5f5284Sbellard #else
1339e5f5284Sbellard #error host_to_target_sigset
1349e5f5284Sbellard #endif
13566fb9763Sbellard }
13666fb9763Sbellard 
1379e5f5284Sbellard void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
13866fb9763Sbellard {
13966fb9763Sbellard     int i;
1409e5f5284Sbellard     unsigned long sigmask;
1419e5f5284Sbellard     target_ulong target_sigmask;
1429e5f5284Sbellard 
1439e5f5284Sbellard     target_sigmask = tswapl(s->sig[0]);
1449e5f5284Sbellard     sigmask = 0;
1459e5f5284Sbellard     for(i = 0; i < 32; i++) {
1469e5f5284Sbellard         if (target_sigmask & (1 << i))
1479e5f5284Sbellard             sigmask |= 1 << (target_to_host_signal(i + 1) - 1);
1489e5f5284Sbellard     }
1499e5f5284Sbellard #if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
1509e5f5284Sbellard     ((unsigned long *)d)[0] = sigmask;
1519e5f5284Sbellard     for(i = 1;i < TARGET_NSIG_WORDS; i++) {
15266fb9763Sbellard         ((unsigned long *)d)[i] = tswapl(s->sig[i]);
15366fb9763Sbellard     }
1549e5f5284Sbellard #elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
1559dfa5b42Sbellard     ((unsigned long *)d)[0] = sigmask | ((unsigned long)tswapl(s->sig[1]) << 32);
1569e5f5284Sbellard #else
1579e5f5284Sbellard #error target_to_host_sigset
1589e5f5284Sbellard #endif /* TARGET_LONG_BITS */
15966fb9763Sbellard }
16066fb9763Sbellard 
16166fb9763Sbellard void host_to_target_old_sigset(target_ulong *old_sigset,
16266fb9763Sbellard                                const sigset_t *sigset)
16366fb9763Sbellard {
1649e5f5284Sbellard     target_sigset_t d;
1659e5f5284Sbellard     host_to_target_sigset(&d, sigset);
1669e5f5284Sbellard     *old_sigset = d.sig[0];
16766fb9763Sbellard }
16866fb9763Sbellard 
16966fb9763Sbellard void target_to_host_old_sigset(sigset_t *sigset,
17066fb9763Sbellard                                const target_ulong *old_sigset)
17166fb9763Sbellard {
1729e5f5284Sbellard     target_sigset_t d;
1739e5f5284Sbellard     int i;
1749e5f5284Sbellard 
1759e5f5284Sbellard     d.sig[0] = *old_sigset;
1769e5f5284Sbellard     for(i = 1;i < TARGET_NSIG_WORDS; i++)
1779e5f5284Sbellard         d.sig[i] = 0;
1789e5f5284Sbellard     target_to_host_sigset(sigset, &d);
17966fb9763Sbellard }
18066fb9763Sbellard 
1819de5e440Sbellard /* siginfo conversion */
1829de5e440Sbellard 
1839de5e440Sbellard static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
1849de5e440Sbellard                                                  const siginfo_t *info)
18566fb9763Sbellard {
1869de5e440Sbellard     int sig;
1879de5e440Sbellard     sig = host_to_target_signal(info->si_signo);
1889de5e440Sbellard     tinfo->si_signo = sig;
1899de5e440Sbellard     tinfo->si_errno = 0;
1909de5e440Sbellard     tinfo->si_code = 0;
191447db213Sbellard     if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
192447db213Sbellard         sig == SIGBUS || sig == SIGTRAP) {
1939de5e440Sbellard         /* should never come here, but who knows. The information for
1949de5e440Sbellard            the target is irrelevant */
1959de5e440Sbellard         tinfo->_sifields._sigfault._addr = 0;
1969de5e440Sbellard     } else if (sig >= TARGET_SIGRTMIN) {
1979de5e440Sbellard         tinfo->_sifields._rt._pid = info->si_pid;
1989de5e440Sbellard         tinfo->_sifields._rt._uid = info->si_uid;
1999de5e440Sbellard         /* XXX: potential problem if 64 bit */
2009de5e440Sbellard         tinfo->_sifields._rt._sigval.sival_ptr =
2019de5e440Sbellard             (target_ulong)info->si_value.sival_ptr;
2029de5e440Sbellard     }
20366fb9763Sbellard }
20466fb9763Sbellard 
2059de5e440Sbellard static void tswap_siginfo(target_siginfo_t *tinfo,
2069de5e440Sbellard                           const target_siginfo_t *info)
2079de5e440Sbellard {
2089de5e440Sbellard     int sig;
2099de5e440Sbellard     sig = info->si_signo;
2109de5e440Sbellard     tinfo->si_signo = tswap32(sig);
2119de5e440Sbellard     tinfo->si_errno = tswap32(info->si_errno);
2129de5e440Sbellard     tinfo->si_code = tswap32(info->si_code);
213447db213Sbellard     if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
214447db213Sbellard         sig == SIGBUS || sig == SIGTRAP) {
2159de5e440Sbellard         tinfo->_sifields._sigfault._addr =
2169de5e440Sbellard             tswapl(info->_sifields._sigfault._addr);
2179de5e440Sbellard     } else if (sig >= TARGET_SIGRTMIN) {
2189de5e440Sbellard         tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
2199de5e440Sbellard         tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
2209de5e440Sbellard         tinfo->_sifields._rt._sigval.sival_ptr =
2219de5e440Sbellard             tswapl(info->_sifields._rt._sigval.sival_ptr);
2229de5e440Sbellard     }
2239de5e440Sbellard }
2249de5e440Sbellard 
2259de5e440Sbellard 
2269de5e440Sbellard void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
2279de5e440Sbellard {
2289de5e440Sbellard     host_to_target_siginfo_noswap(tinfo, info);
2299de5e440Sbellard     tswap_siginfo(tinfo, tinfo);
2309de5e440Sbellard }
2319de5e440Sbellard 
2329de5e440Sbellard /* XXX: we support only POSIX RT signals are used. */
2339de5e440Sbellard /* XXX: find a solution for 64 bit (additionnal malloced data is needed) */
2349de5e440Sbellard void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
23566fb9763Sbellard {
23666fb9763Sbellard     info->si_signo = tswap32(tinfo->si_signo);
23766fb9763Sbellard     info->si_errno = tswap32(tinfo->si_errno);
23866fb9763Sbellard     info->si_code = tswap32(tinfo->si_code);
2399de5e440Sbellard     info->si_pid = tswap32(tinfo->_sifields._rt._pid);
2409de5e440Sbellard     info->si_uid = tswap32(tinfo->_sifields._rt._uid);
2419de5e440Sbellard     info->si_value.sival_ptr =
2429de5e440Sbellard         (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
24366fb9763Sbellard }
24466fb9763Sbellard 
24531e31b8aSbellard void signal_init(void)
24631e31b8aSbellard {
24731e31b8aSbellard     struct sigaction act;
2489e5f5284Sbellard     int i, j;
2499e5f5284Sbellard 
2509e5f5284Sbellard     /* generate signal conversion tables */
2519e5f5284Sbellard     for(i = 1; i <= 64; i++) {
2529e5f5284Sbellard         if (host_to_target_signal_table[i] == 0)
2539e5f5284Sbellard             host_to_target_signal_table[i] = i;
2549e5f5284Sbellard     }
2559e5f5284Sbellard     for(i = 1; i <= 64; i++) {
2569e5f5284Sbellard         j = host_to_target_signal_table[i];
2579e5f5284Sbellard         target_to_host_signal_table[j] = i;
2589e5f5284Sbellard     }
25931e31b8aSbellard 
2609de5e440Sbellard     /* set all host signal handlers. ALL signals are blocked during
2619de5e440Sbellard        the handlers to serialize them. */
2629de5e440Sbellard     sigfillset(&act.sa_mask);
26331e31b8aSbellard     act.sa_flags = SA_SIGINFO;
26431e31b8aSbellard     act.sa_sigaction = host_signal_handler;
26531e31b8aSbellard     for(i = 1; i < NSIG; i++) {
26666fb9763Sbellard         sigaction(i, &act, NULL);
26731e31b8aSbellard     }
26831e31b8aSbellard 
26931e31b8aSbellard     memset(sigact_table, 0, sizeof(sigact_table));
27066fb9763Sbellard 
27166fb9763Sbellard     first_free = &sigqueue_table[0];
27266fb9763Sbellard     for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
27366fb9763Sbellard         sigqueue_table[i].next = &sigqueue_table[i + 1];
27466fb9763Sbellard     sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
27531e31b8aSbellard }
27631e31b8aSbellard 
27766fb9763Sbellard /* signal queue handling */
27866fb9763Sbellard 
27966fb9763Sbellard static inline struct sigqueue *alloc_sigqueue(void)
28066fb9763Sbellard {
28166fb9763Sbellard     struct sigqueue *q = first_free;
28266fb9763Sbellard     if (!q)
28366fb9763Sbellard         return NULL;
28466fb9763Sbellard     first_free = q->next;
28566fb9763Sbellard     return q;
28666fb9763Sbellard }
28766fb9763Sbellard 
28866fb9763Sbellard static inline void free_sigqueue(struct sigqueue *q)
28966fb9763Sbellard {
29066fb9763Sbellard     q->next = first_free;
29166fb9763Sbellard     first_free = q;
29266fb9763Sbellard }
29366fb9763Sbellard 
2949de5e440Sbellard /* abort execution with signal */
2959de5e440Sbellard void __attribute((noreturn)) force_sig(int sig)
29666fb9763Sbellard {
2979de5e440Sbellard     int host_sig;
2989de5e440Sbellard     host_sig = target_to_host_signal(sig);
299bc8a22ccSbellard     fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
3009de5e440Sbellard             sig, strsignal(host_sig));
3019de5e440Sbellard #if 1
3029de5e440Sbellard     _exit(-host_sig);
3039de5e440Sbellard #else
3049de5e440Sbellard     {
3059de5e440Sbellard         struct sigaction act;
3069de5e440Sbellard         sigemptyset(&act.sa_mask);
3079de5e440Sbellard         act.sa_flags = SA_SIGINFO;
3089de5e440Sbellard         act.sa_sigaction = SIG_DFL;
3099de5e440Sbellard         sigaction(SIGABRT, &act, NULL);
3109de5e440Sbellard         abort();
3119de5e440Sbellard     }
3129de5e440Sbellard #endif
3139de5e440Sbellard }
31466fb9763Sbellard 
3159de5e440Sbellard /* queue a signal so that it will be send to the virtual CPU as soon
3169de5e440Sbellard    as possible */
3179de5e440Sbellard int queue_signal(int sig, target_siginfo_t *info)
3189de5e440Sbellard {
3199de5e440Sbellard     struct emulated_sigaction *k;
3209de5e440Sbellard     struct sigqueue *q, **pq;
3219de5e440Sbellard     target_ulong handler;
3229de5e440Sbellard 
3239de5e440Sbellard #if defined(DEBUG_SIGNAL)
324bc8a22ccSbellard     fprintf(stderr, "queue_signal: sig=%d\n",
3259de5e440Sbellard             sig);
3269de5e440Sbellard #endif
3279de5e440Sbellard     k = &sigact_table[sig - 1];
3289de5e440Sbellard     handler = k->sa._sa_handler;
3299de5e440Sbellard     if (handler == TARGET_SIG_DFL) {
3309de5e440Sbellard         /* default handler : ignore some signal. The other are fatal */
3319de5e440Sbellard         if (sig != TARGET_SIGCHLD &&
3329de5e440Sbellard             sig != TARGET_SIGURG &&
3339de5e440Sbellard             sig != TARGET_SIGWINCH) {
3349de5e440Sbellard             force_sig(sig);
3359de5e440Sbellard         } else {
3369de5e440Sbellard             return 0; /* indicate ignored */
3379de5e440Sbellard         }
3389de5e440Sbellard     } else if (handler == TARGET_SIG_IGN) {
3399de5e440Sbellard         /* ignore signal */
3409de5e440Sbellard         return 0;
3419de5e440Sbellard     } else if (handler == TARGET_SIG_ERR) {
3429de5e440Sbellard         force_sig(sig);
3439de5e440Sbellard     } else {
34466fb9763Sbellard         pq = &k->first;
3459de5e440Sbellard         if (sig < TARGET_SIGRTMIN) {
3469de5e440Sbellard             /* if non real time signal, we queue exactly one signal */
3479de5e440Sbellard             if (!k->pending)
3489de5e440Sbellard                 q = &k->info;
3499de5e440Sbellard             else
3509de5e440Sbellard                 return 0;
3519de5e440Sbellard         } else {
3529de5e440Sbellard             if (!k->pending) {
3539de5e440Sbellard                 /* first signal */
35466fb9763Sbellard                 q = &k->info;
35566fb9763Sbellard             } else {
35666fb9763Sbellard                 q = alloc_sigqueue();
35766fb9763Sbellard                 if (!q)
35866fb9763Sbellard                     return -EAGAIN;
35966fb9763Sbellard                 while (*pq != NULL)
36066fb9763Sbellard                     pq = &(*pq)->next;
36166fb9763Sbellard             }
3629de5e440Sbellard         }
36366fb9763Sbellard         *pq = q;
36466fb9763Sbellard         q->info = *info;
36566fb9763Sbellard         q->next = NULL;
36666fb9763Sbellard         k->pending = 1;
36766fb9763Sbellard         /* signal that a new signal is pending */
36866fb9763Sbellard         signal_pending = 1;
3699de5e440Sbellard         return 1; /* indicates that the signal was queued */
3709de5e440Sbellard     }
37166fb9763Sbellard }
37266fb9763Sbellard 
37331e31b8aSbellard static void host_signal_handler(int host_signum, siginfo_t *info,
37431e31b8aSbellard                                 void *puc)
37531e31b8aSbellard {
37666fb9763Sbellard     int sig;
3779de5e440Sbellard     target_siginfo_t tinfo;
3789de5e440Sbellard 
3799de5e440Sbellard     /* the CPU emulator uses some host signals to detect exceptions,
3809de5e440Sbellard        we we forward to it some signals */
3819de5e440Sbellard     if (host_signum == SIGSEGV || host_signum == SIGBUS) {
382b346ff46Sbellard         if (cpu_signal_handler(host_signum, info, puc))
3839de5e440Sbellard             return;
3849de5e440Sbellard     }
38566fb9763Sbellard 
38631e31b8aSbellard     /* get target signal number */
38766fb9763Sbellard     sig = host_to_target_signal(host_signum);
38866fb9763Sbellard     if (sig < 1 || sig > TARGET_NSIG)
38931e31b8aSbellard         return;
3909de5e440Sbellard #if defined(DEBUG_SIGNAL)
391bc8a22ccSbellard     fprintf(stderr, "qemu: got signal %d\n", sig);
39266fb9763Sbellard #endif
3939de5e440Sbellard     host_to_target_siginfo_noswap(&tinfo, info);
3949de5e440Sbellard     if (queue_signal(sig, &tinfo) == 1) {
3959de5e440Sbellard         /* interrupt the virtual CPU as soon as possible */
39668a79315Sbellard         cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
39766fb9763Sbellard     }
39831e31b8aSbellard }
39931e31b8aSbellard 
40066fb9763Sbellard int do_sigaction(int sig, const struct target_sigaction *act,
40166fb9763Sbellard                  struct target_sigaction *oact)
40231e31b8aSbellard {
40366fb9763Sbellard     struct emulated_sigaction *k;
404*773b93eeSbellard     struct sigaction act1;
405*773b93eeSbellard     int host_sig;
40631e31b8aSbellard 
40766fb9763Sbellard     if (sig < 1 || sig > TARGET_NSIG)
40866fb9763Sbellard         return -EINVAL;
40966fb9763Sbellard     k = &sigact_table[sig - 1];
410*773b93eeSbellard #if defined(DEBUG_SIGNAL)
41166fb9763Sbellard     fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
41266fb9763Sbellard             sig, (int)act, (int)oact);
41366fb9763Sbellard #endif
41466fb9763Sbellard     if (oact) {
41566fb9763Sbellard         oact->_sa_handler = tswapl(k->sa._sa_handler);
41666fb9763Sbellard         oact->sa_flags = tswapl(k->sa.sa_flags);
41766fb9763Sbellard         oact->sa_restorer = tswapl(k->sa.sa_restorer);
41866fb9763Sbellard         oact->sa_mask = k->sa.sa_mask;
41966fb9763Sbellard     }
42066fb9763Sbellard     if (act) {
42166fb9763Sbellard         k->sa._sa_handler = tswapl(act->_sa_handler);
42266fb9763Sbellard         k->sa.sa_flags = tswapl(act->sa_flags);
42366fb9763Sbellard         k->sa.sa_restorer = tswapl(act->sa_restorer);
42466fb9763Sbellard         k->sa.sa_mask = act->sa_mask;
425*773b93eeSbellard 
426*773b93eeSbellard         /* we update the host linux signal state */
427*773b93eeSbellard         host_sig = target_to_host_signal(sig);
428*773b93eeSbellard         if (host_sig != SIGSEGV && host_sig != SIGBUS) {
429*773b93eeSbellard             sigfillset(&act1.sa_mask);
430*773b93eeSbellard             act1.sa_flags = SA_SIGINFO;
431*773b93eeSbellard             if (k->sa.sa_flags & TARGET_SA_RESTART)
432*773b93eeSbellard                 act1.sa_flags |= SA_RESTART;
433*773b93eeSbellard             /* NOTE: it is important to update the host kernel signal
434*773b93eeSbellard                ignore state to avoid getting unexpected interrupted
435*773b93eeSbellard                syscalls */
436*773b93eeSbellard             if (k->sa._sa_handler == TARGET_SIG_IGN) {
437*773b93eeSbellard                 act1.sa_sigaction = (void *)SIG_IGN;
438*773b93eeSbellard             } else if (k->sa._sa_handler == TARGET_SIG_DFL) {
439*773b93eeSbellard                 act1.sa_sigaction = (void *)SIG_DFL;
440*773b93eeSbellard             } else {
441*773b93eeSbellard                 act1.sa_sigaction = host_signal_handler;
442*773b93eeSbellard             }
443*773b93eeSbellard             sigaction(host_sig, &act1, NULL);
444*773b93eeSbellard         }
44566fb9763Sbellard     }
44666fb9763Sbellard     return 0;
44766fb9763Sbellard }
44866fb9763Sbellard 
44943fff238Sbellard #define __put_user(x,ptr)\
45043fff238Sbellard ({\
45143fff238Sbellard     int size = sizeof(*ptr);\
45243fff238Sbellard     switch(size) {\
45343fff238Sbellard     case 1:\
45443fff238Sbellard         stb(ptr, (typeof(*ptr))(x));\
45543fff238Sbellard         break;\
45643fff238Sbellard     case 2:\
45743fff238Sbellard         stw(ptr, (typeof(*ptr))(x));\
45843fff238Sbellard         break;\
45943fff238Sbellard     case 4:\
46043fff238Sbellard         stl(ptr, (typeof(*ptr))(x));\
46143fff238Sbellard         break;\
46243fff238Sbellard     case 8:\
46343fff238Sbellard         stq(ptr, (typeof(*ptr))(x));\
46443fff238Sbellard         break;\
46543fff238Sbellard     default:\
46643fff238Sbellard         abort();\
46743fff238Sbellard     }\
46843fff238Sbellard     0;\
46943fff238Sbellard })
47043fff238Sbellard 
47143fff238Sbellard #define __get_user(x, ptr) \
47243fff238Sbellard ({\
47343fff238Sbellard     int size = sizeof(*ptr);\
47443fff238Sbellard     switch(size) {\
47543fff238Sbellard     case 1:\
47643fff238Sbellard         x = (typeof(*ptr))ldub(ptr);\
47743fff238Sbellard         break;\
47843fff238Sbellard     case 2:\
47943fff238Sbellard         x = (typeof(*ptr))lduw(ptr);\
48043fff238Sbellard         break;\
48143fff238Sbellard     case 4:\
48243fff238Sbellard         x = (typeof(*ptr))ldl(ptr);\
48343fff238Sbellard         break;\
48443fff238Sbellard     case 8:\
48543fff238Sbellard         x = (typeof(*ptr))ldq(ptr);\
48643fff238Sbellard         break;\
48743fff238Sbellard     default:\
48843fff238Sbellard         abort();\
48943fff238Sbellard     }\
49043fff238Sbellard     0;\
49143fff238Sbellard })
49243fff238Sbellard 
49343fff238Sbellard 
49443fff238Sbellard #define __copy_to_user(dst, src, size)\
49543fff238Sbellard ({\
49643fff238Sbellard     memcpy(dst, src, size);\
49743fff238Sbellard     0;\
49843fff238Sbellard })
49943fff238Sbellard 
50043fff238Sbellard #define __copy_from_user(dst, src, size)\
50143fff238Sbellard ({\
50243fff238Sbellard     memcpy(dst, src, size);\
50343fff238Sbellard     0;\
50443fff238Sbellard })
50543fff238Sbellard 
50643fff238Sbellard #define __clear_user(dst, size)\
50743fff238Sbellard ({\
50843fff238Sbellard     memset(dst, 0, size);\
50943fff238Sbellard     0;\
51043fff238Sbellard })
51143fff238Sbellard 
51243fff238Sbellard #ifndef offsetof
51343fff238Sbellard #define offsetof(type, field) ((size_t) &((type *)0)->field)
51443fff238Sbellard #endif
51543fff238Sbellard 
51643fff238Sbellard static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
51743fff238Sbellard                                        const target_siginfo_t *info)
51843fff238Sbellard {
51943fff238Sbellard     tswap_siginfo(tinfo, info);
52043fff238Sbellard     return 0;
52143fff238Sbellard }
52243fff238Sbellard 
52366fb9763Sbellard #ifdef TARGET_I386
52466fb9763Sbellard 
52566fb9763Sbellard /* from the Linux kernel */
52666fb9763Sbellard 
52766fb9763Sbellard struct target_fpreg {
52866fb9763Sbellard 	uint16_t significand[4];
52966fb9763Sbellard 	uint16_t exponent;
53066fb9763Sbellard };
53166fb9763Sbellard 
53266fb9763Sbellard struct target_fpxreg {
53366fb9763Sbellard 	uint16_t significand[4];
53466fb9763Sbellard 	uint16_t exponent;
53566fb9763Sbellard 	uint16_t padding[3];
53666fb9763Sbellard };
53766fb9763Sbellard 
53866fb9763Sbellard struct target_xmmreg {
53966fb9763Sbellard 	target_ulong element[4];
54066fb9763Sbellard };
54166fb9763Sbellard 
54266fb9763Sbellard struct target_fpstate {
54366fb9763Sbellard 	/* Regular FPU environment */
54466fb9763Sbellard 	target_ulong 	cw;
54566fb9763Sbellard 	target_ulong	sw;
54666fb9763Sbellard 	target_ulong	tag;
54766fb9763Sbellard 	target_ulong	ipoff;
54866fb9763Sbellard 	target_ulong	cssel;
54966fb9763Sbellard 	target_ulong	dataoff;
55066fb9763Sbellard 	target_ulong	datasel;
55166fb9763Sbellard 	struct target_fpreg	_st[8];
55266fb9763Sbellard 	uint16_t	status;
55366fb9763Sbellard 	uint16_t	magic;		/* 0xffff = regular FPU data only */
55466fb9763Sbellard 
55566fb9763Sbellard 	/* FXSR FPU environment */
55666fb9763Sbellard 	target_ulong	_fxsr_env[6];	/* FXSR FPU env is ignored */
55766fb9763Sbellard 	target_ulong	mxcsr;
55866fb9763Sbellard 	target_ulong	reserved;
55966fb9763Sbellard 	struct target_fpxreg	_fxsr_st[8];	/* FXSR FPU reg data is ignored */
56066fb9763Sbellard 	struct target_xmmreg	_xmm[8];
56166fb9763Sbellard 	target_ulong	padding[56];
56266fb9763Sbellard };
56366fb9763Sbellard 
56466fb9763Sbellard #define X86_FXSR_MAGIC		0x0000
56566fb9763Sbellard 
56666fb9763Sbellard struct target_sigcontext {
56766fb9763Sbellard 	uint16_t gs, __gsh;
56866fb9763Sbellard 	uint16_t fs, __fsh;
56966fb9763Sbellard 	uint16_t es, __esh;
57066fb9763Sbellard 	uint16_t ds, __dsh;
57166fb9763Sbellard 	target_ulong edi;
57266fb9763Sbellard 	target_ulong esi;
57366fb9763Sbellard 	target_ulong ebp;
57466fb9763Sbellard 	target_ulong esp;
57566fb9763Sbellard 	target_ulong ebx;
57666fb9763Sbellard 	target_ulong edx;
57766fb9763Sbellard 	target_ulong ecx;
57866fb9763Sbellard 	target_ulong eax;
57966fb9763Sbellard 	target_ulong trapno;
58066fb9763Sbellard 	target_ulong err;
58166fb9763Sbellard 	target_ulong eip;
58266fb9763Sbellard 	uint16_t cs, __csh;
58366fb9763Sbellard 	target_ulong eflags;
58466fb9763Sbellard 	target_ulong esp_at_signal;
58566fb9763Sbellard 	uint16_t ss, __ssh;
58666fb9763Sbellard         target_ulong fpstate; /* pointer */
58766fb9763Sbellard 	target_ulong oldmask;
58866fb9763Sbellard 	target_ulong cr2;
58966fb9763Sbellard };
59066fb9763Sbellard 
59166fb9763Sbellard typedef struct target_sigaltstack {
59266fb9763Sbellard 	target_ulong ss_sp;
59366fb9763Sbellard 	int ss_flags;
59466fb9763Sbellard 	target_ulong ss_size;
59566fb9763Sbellard } target_stack_t;
59666fb9763Sbellard 
59766fb9763Sbellard struct target_ucontext {
59866fb9763Sbellard         target_ulong	  uc_flags;
59966fb9763Sbellard 	target_ulong      uc_link;
60066fb9763Sbellard 	target_stack_t	  uc_stack;
60166fb9763Sbellard 	struct target_sigcontext uc_mcontext;
60266fb9763Sbellard 	target_sigset_t	  uc_sigmask;	/* mask last for extensibility */
60366fb9763Sbellard };
60466fb9763Sbellard 
60566fb9763Sbellard struct sigframe
60666fb9763Sbellard {
60766fb9763Sbellard     target_ulong pretcode;
60866fb9763Sbellard     int sig;
60966fb9763Sbellard     struct target_sigcontext sc;
61066fb9763Sbellard     struct target_fpstate fpstate;
61166fb9763Sbellard     target_ulong extramask[TARGET_NSIG_WORDS-1];
61266fb9763Sbellard     char retcode[8];
61366fb9763Sbellard };
61466fb9763Sbellard 
61566fb9763Sbellard struct rt_sigframe
61666fb9763Sbellard {
61766fb9763Sbellard     target_ulong pretcode;
61866fb9763Sbellard     int sig;
61966fb9763Sbellard     target_ulong pinfo;
62066fb9763Sbellard     target_ulong puc;
62166fb9763Sbellard     struct target_siginfo info;
62266fb9763Sbellard     struct target_ucontext uc;
62366fb9763Sbellard     struct target_fpstate fpstate;
62466fb9763Sbellard     char retcode[8];
62566fb9763Sbellard };
62666fb9763Sbellard 
62766fb9763Sbellard /*
62866fb9763Sbellard  * Set up a signal frame.
62966fb9763Sbellard  */
63066fb9763Sbellard 
63166fb9763Sbellard /* XXX: save x87 state */
63266fb9763Sbellard static int
63366fb9763Sbellard setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
63466fb9763Sbellard 		 CPUX86State *env, unsigned long mask)
63566fb9763Sbellard {
63666fb9763Sbellard 	int err = 0;
63766fb9763Sbellard 
638a52c757cSbellard 	err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
639a52c757cSbellard 	err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
640a52c757cSbellard 	err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
641a52c757cSbellard 	err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
64266fb9763Sbellard 	err |= __put_user(env->regs[R_EDI], &sc->edi);
64366fb9763Sbellard 	err |= __put_user(env->regs[R_ESI], &sc->esi);
64466fb9763Sbellard 	err |= __put_user(env->regs[R_EBP], &sc->ebp);
64566fb9763Sbellard 	err |= __put_user(env->regs[R_ESP], &sc->esp);
64666fb9763Sbellard 	err |= __put_user(env->regs[R_EBX], &sc->ebx);
64766fb9763Sbellard 	err |= __put_user(env->regs[R_EDX], &sc->edx);
64866fb9763Sbellard 	err |= __put_user(env->regs[R_ECX], &sc->ecx);
64966fb9763Sbellard 	err |= __put_user(env->regs[R_EAX], &sc->eax);
65066099dd9Sbellard 	err |= __put_user(env->exception_index, &sc->trapno);
65166099dd9Sbellard 	err |= __put_user(env->error_code, &sc->err);
65266fb9763Sbellard 	err |= __put_user(env->eip, &sc->eip);
653a52c757cSbellard 	err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
65466fb9763Sbellard 	err |= __put_user(env->eflags, &sc->eflags);
65566fb9763Sbellard 	err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
656a52c757cSbellard 	err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
657ed2dcdf6Sbellard 
658ed2dcdf6Sbellard         cpu_x86_fsave(env, (void *)fpstate, 1);
659ed2dcdf6Sbellard         fpstate->status = fpstate->sw;
660ed2dcdf6Sbellard         err |= __put_user(0xffff, &fpstate->magic);
661ed2dcdf6Sbellard         err |= __put_user(fpstate, &sc->fpstate);
662ed2dcdf6Sbellard 
66366fb9763Sbellard 	/* non-iBCS2 extensions.. */
66466fb9763Sbellard 	err |= __put_user(mask, &sc->oldmask);
665a52c757cSbellard 	err |= __put_user(env->cr[2], &sc->cr2);
66666fb9763Sbellard 	return err;
66766fb9763Sbellard }
66866fb9763Sbellard 
66966fb9763Sbellard /*
67066fb9763Sbellard  * Determine which stack to use..
67166fb9763Sbellard  */
67266fb9763Sbellard 
67366fb9763Sbellard static inline void *
67466fb9763Sbellard get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
67566fb9763Sbellard {
67666fb9763Sbellard 	unsigned long esp;
67766fb9763Sbellard 
67866fb9763Sbellard 	/* Default to using normal stack */
67966fb9763Sbellard 	esp = env->regs[R_ESP];
68066fb9763Sbellard #if 0
68166fb9763Sbellard 	/* This is the X/Open sanctioned signal stack switching.  */
68266fb9763Sbellard 	if (ka->sa.sa_flags & SA_ONSTACK) {
68366fb9763Sbellard 		if (sas_ss_flags(esp) == 0)
68466fb9763Sbellard 			esp = current->sas_ss_sp + current->sas_ss_size;
68566fb9763Sbellard 	}
68666fb9763Sbellard 
68766fb9763Sbellard 	/* This is the legacy signal stack switching. */
688a52c757cSbellard 	else
689a52c757cSbellard #endif
690a52c757cSbellard         if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
691a52c757cSbellard             !(ka->sa.sa_flags & TARGET_SA_RESTORER) &&
69266fb9763Sbellard             ka->sa.sa_restorer) {
69366fb9763Sbellard             esp = (unsigned long) ka->sa.sa_restorer;
69466fb9763Sbellard 	}
69566fb9763Sbellard         return (void *)((esp - frame_size) & -8ul);
69666fb9763Sbellard }
69766fb9763Sbellard 
69866fb9763Sbellard static void setup_frame(int sig, struct emulated_sigaction *ka,
69966fb9763Sbellard 			target_sigset_t *set, CPUX86State *env)
70066fb9763Sbellard {
70166fb9763Sbellard 	struct sigframe *frame;
70266fb9763Sbellard 	int err = 0;
70366fb9763Sbellard 
70466fb9763Sbellard 	frame = get_sigframe(ka, env, sizeof(*frame));
70566fb9763Sbellard 
70666fb9763Sbellard #if 0
70766fb9763Sbellard 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
70866fb9763Sbellard 		goto give_sigsegv;
70966fb9763Sbellard #endif
71066fb9763Sbellard 	err |= __put_user((/*current->exec_domain
71166fb9763Sbellard 		           && current->exec_domain->signal_invmap
71266fb9763Sbellard 		           && sig < 32
71366fb9763Sbellard 		           ? current->exec_domain->signal_invmap[sig]
71466fb9763Sbellard 		           : */ sig),
71566fb9763Sbellard 		          &frame->sig);
71666fb9763Sbellard 	if (err)
71766fb9763Sbellard 		goto give_sigsegv;
71866fb9763Sbellard 
71966fb9763Sbellard 	setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0]);
72066fb9763Sbellard 	if (err)
72166fb9763Sbellard 		goto give_sigsegv;
72266fb9763Sbellard 
72366fb9763Sbellard 	if (TARGET_NSIG_WORDS > 1) {
72466fb9763Sbellard 		err |= __copy_to_user(frame->extramask, &set->sig[1],
72566fb9763Sbellard 				      sizeof(frame->extramask));
72666fb9763Sbellard 	}
72766fb9763Sbellard 	if (err)
72866fb9763Sbellard 		goto give_sigsegv;
72966fb9763Sbellard 
73066fb9763Sbellard 	/* Set up to return from userspace.  If provided, use a stub
73166fb9763Sbellard 	   already in userspace.  */
73266fb9763Sbellard 	if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
73366fb9763Sbellard 		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
73466fb9763Sbellard 	} else {
73566fb9763Sbellard 		err |= __put_user(frame->retcode, &frame->pretcode);
73666fb9763Sbellard 		/* This is popl %eax ; movl $,%eax ; int $0x80 */
73766fb9763Sbellard 		err |= __put_user(0xb858, (short *)(frame->retcode+0));
73866fb9763Sbellard 		err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
73966fb9763Sbellard 		err |= __put_user(0x80cd, (short *)(frame->retcode+6));
74066fb9763Sbellard 	}
74166fb9763Sbellard 
74266fb9763Sbellard 	if (err)
74366fb9763Sbellard 		goto give_sigsegv;
74466fb9763Sbellard 
74566fb9763Sbellard 	/* Set up registers for signal handler */
74666fb9763Sbellard 	env->regs[R_ESP] = (unsigned long) frame;
74766fb9763Sbellard 	env->eip = (unsigned long) ka->sa._sa_handler;
74866fb9763Sbellard 
74966fb9763Sbellard         cpu_x86_load_seg(env, R_DS, __USER_DS);
75066fb9763Sbellard         cpu_x86_load_seg(env, R_ES, __USER_DS);
75166fb9763Sbellard         cpu_x86_load_seg(env, R_SS, __USER_DS);
75266fb9763Sbellard         cpu_x86_load_seg(env, R_CS, __USER_CS);
75366fb9763Sbellard 	env->eflags &= ~TF_MASK;
75466fb9763Sbellard 
75566fb9763Sbellard 	return;
75666fb9763Sbellard 
75766fb9763Sbellard give_sigsegv:
75866fb9763Sbellard 	if (sig == TARGET_SIGSEGV)
75966fb9763Sbellard 		ka->sa._sa_handler = TARGET_SIG_DFL;
76066fb9763Sbellard 	force_sig(TARGET_SIGSEGV /* , current */);
76166fb9763Sbellard }
76266fb9763Sbellard 
7639de5e440Sbellard static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
7649de5e440Sbellard                            target_siginfo_t *info,
76566fb9763Sbellard 			   target_sigset_t *set, CPUX86State *env)
76666fb9763Sbellard {
76766fb9763Sbellard 	struct rt_sigframe *frame;
76866fb9763Sbellard 	int err = 0;
76966fb9763Sbellard 
77066fb9763Sbellard 	frame = get_sigframe(ka, env, sizeof(*frame));
77166fb9763Sbellard 
77266fb9763Sbellard #if 0
77366fb9763Sbellard 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
77466fb9763Sbellard 		goto give_sigsegv;
77566fb9763Sbellard #endif
77666fb9763Sbellard 
77766fb9763Sbellard 	err |= __put_user((/*current->exec_domain
77866fb9763Sbellard 		    	   && current->exec_domain->signal_invmap
77966fb9763Sbellard 		    	   && sig < 32
78066fb9763Sbellard 		    	   ? current->exec_domain->signal_invmap[sig]
78166fb9763Sbellard 			   : */sig),
78266fb9763Sbellard 			  &frame->sig);
78366fb9763Sbellard 	err |= __put_user((target_ulong)&frame->info, &frame->pinfo);
78466fb9763Sbellard 	err |= __put_user((target_ulong)&frame->uc, &frame->puc);
78566fb9763Sbellard 	err |= copy_siginfo_to_user(&frame->info, info);
78666fb9763Sbellard 	if (err)
78766fb9763Sbellard 		goto give_sigsegv;
78866fb9763Sbellard 
78966fb9763Sbellard 	/* Create the ucontext.  */
79066fb9763Sbellard 	err |= __put_user(0, &frame->uc.uc_flags);
79166fb9763Sbellard 	err |= __put_user(0, &frame->uc.uc_link);
79266fb9763Sbellard 	err |= __put_user(/*current->sas_ss_sp*/ 0, &frame->uc.uc_stack.ss_sp);
79366fb9763Sbellard 	err |= __put_user(/* sas_ss_flags(regs->esp) */ 0,
79466fb9763Sbellard 			  &frame->uc.uc_stack.ss_flags);
79566fb9763Sbellard 	err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size);
79666fb9763Sbellard 	err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
79766fb9763Sbellard 			        env, set->sig[0]);
79866fb9763Sbellard 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
79966fb9763Sbellard 	if (err)
80066fb9763Sbellard 		goto give_sigsegv;
80166fb9763Sbellard 
80266fb9763Sbellard 	/* Set up to return from userspace.  If provided, use a stub
80366fb9763Sbellard 	   already in userspace.  */
80466fb9763Sbellard 	if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
80566fb9763Sbellard 		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
80666fb9763Sbellard 	} else {
80766fb9763Sbellard 		err |= __put_user(frame->retcode, &frame->pretcode);
80866fb9763Sbellard 		/* This is movl $,%eax ; int $0x80 */
80966fb9763Sbellard 		err |= __put_user(0xb8, (char *)(frame->retcode+0));
81066fb9763Sbellard 		err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
81166fb9763Sbellard 		err |= __put_user(0x80cd, (short *)(frame->retcode+5));
81266fb9763Sbellard 	}
81366fb9763Sbellard 
81466fb9763Sbellard 	if (err)
81566fb9763Sbellard 		goto give_sigsegv;
81666fb9763Sbellard 
81766fb9763Sbellard 	/* Set up registers for signal handler */
81866fb9763Sbellard 	env->regs[R_ESP] = (unsigned long) frame;
81966fb9763Sbellard 	env->eip = (unsigned long) ka->sa._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 
82766fb9763Sbellard 	return;
82866fb9763Sbellard 
82966fb9763Sbellard give_sigsegv:
83066fb9763Sbellard 	if (sig == TARGET_SIGSEGV)
83166fb9763Sbellard 		ka->sa._sa_handler = TARGET_SIG_DFL;
83266fb9763Sbellard 	force_sig(TARGET_SIGSEGV /* , current */);
83366fb9763Sbellard }
83466fb9763Sbellard 
83566fb9763Sbellard static int
83666fb9763Sbellard restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
83766fb9763Sbellard {
83866fb9763Sbellard 	unsigned int err = 0;
83966fb9763Sbellard 
84066fb9763Sbellard         cpu_x86_load_seg(env, R_GS, lduw(&sc->gs));
84166fb9763Sbellard         cpu_x86_load_seg(env, R_FS, lduw(&sc->fs));
84266fb9763Sbellard         cpu_x86_load_seg(env, R_ES, lduw(&sc->es));
84366fb9763Sbellard         cpu_x86_load_seg(env, R_DS, lduw(&sc->ds));
84466fb9763Sbellard 
84566fb9763Sbellard         env->regs[R_EDI] = ldl(&sc->edi);
84666fb9763Sbellard         env->regs[R_ESI] = ldl(&sc->esi);
84766fb9763Sbellard         env->regs[R_EBP] = ldl(&sc->ebp);
84866fb9763Sbellard         env->regs[R_ESP] = ldl(&sc->esp);
84966fb9763Sbellard         env->regs[R_EBX] = ldl(&sc->ebx);
85066fb9763Sbellard         env->regs[R_EDX] = ldl(&sc->edx);
85166fb9763Sbellard         env->regs[R_ECX] = ldl(&sc->ecx);
85266fb9763Sbellard         env->eip = ldl(&sc->eip);
85366fb9763Sbellard 
85466fb9763Sbellard         cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
85566fb9763Sbellard         cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
85666fb9763Sbellard 
85766fb9763Sbellard 	{
85866fb9763Sbellard 		unsigned int tmpflags;
85966fb9763Sbellard                 tmpflags = ldl(&sc->eflags);
86066fb9763Sbellard 		env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
86166fb9763Sbellard                 //		regs->orig_eax = -1;		/* disable syscall checks */
86266fb9763Sbellard 	}
86366fb9763Sbellard 
86466fb9763Sbellard 	{
86566fb9763Sbellard 		struct _fpstate * buf;
866ed2dcdf6Sbellard                 buf = (void *)ldl(&sc->fpstate);
86766fb9763Sbellard 		if (buf) {
868ed2dcdf6Sbellard #if 0
86966fb9763Sbellard 			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
87066fb9763Sbellard 				goto badframe;
87166fb9763Sbellard #endif
872ed2dcdf6Sbellard                         cpu_x86_frstor(env, (void *)buf, 1);
873ed2dcdf6Sbellard 		}
874ed2dcdf6Sbellard 	}
875ed2dcdf6Sbellard 
87666fb9763Sbellard         *peax = ldl(&sc->eax);
87766fb9763Sbellard 	return err;
87866fb9763Sbellard #if 0
87966fb9763Sbellard badframe:
88066fb9763Sbellard 	return 1;
88166fb9763Sbellard #endif
88266fb9763Sbellard }
88366fb9763Sbellard 
88466fb9763Sbellard long do_sigreturn(CPUX86State *env)
88566fb9763Sbellard {
88666fb9763Sbellard     struct sigframe *frame = (struct sigframe *)(env->regs[R_ESP] - 8);
88766fb9763Sbellard     target_sigset_t target_set;
88866fb9763Sbellard     sigset_t set;
88966fb9763Sbellard     int eax, i;
89066fb9763Sbellard 
891447db213Sbellard #if defined(DEBUG_SIGNAL)
892447db213Sbellard     fprintf(stderr, "do_sigreturn\n");
893447db213Sbellard #endif
89466fb9763Sbellard     /* set blocked signals */
89566fb9763Sbellard     target_set.sig[0] = frame->sc.oldmask;
89666fb9763Sbellard     for(i = 1; i < TARGET_NSIG_WORDS; i++)
89766fb9763Sbellard         target_set.sig[i] = frame->extramask[i - 1];
89866fb9763Sbellard 
89966fb9763Sbellard     target_to_host_sigset(&set, &target_set);
90066fb9763Sbellard     sigprocmask(SIG_SETMASK, &set, NULL);
90166fb9763Sbellard 
90266fb9763Sbellard     /* restore registers */
90366fb9763Sbellard     if (restore_sigcontext(env, &frame->sc, &eax))
90466fb9763Sbellard         goto badframe;
90566fb9763Sbellard     return eax;
90666fb9763Sbellard 
90766fb9763Sbellard badframe:
90866fb9763Sbellard     force_sig(TARGET_SIGSEGV);
90966fb9763Sbellard     return 0;
91066fb9763Sbellard }
91166fb9763Sbellard 
91266fb9763Sbellard long do_rt_sigreturn(CPUX86State *env)
91366fb9763Sbellard {
91466fb9763Sbellard 	struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4);
91566fb9763Sbellard 	target_sigset_t target_set;
91666fb9763Sbellard         sigset_t set;
91766fb9763Sbellard         //	stack_t st;
91866fb9763Sbellard 	int eax;
91966fb9763Sbellard 
92066fb9763Sbellard #if 0
92166fb9763Sbellard 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
92266fb9763Sbellard 		goto badframe;
92366fb9763Sbellard #endif
92466fb9763Sbellard         memcpy(&target_set, &frame->uc.uc_sigmask, sizeof(target_sigset_t));
92566fb9763Sbellard 
92666fb9763Sbellard         target_to_host_sigset(&set, &target_set);
92766fb9763Sbellard         sigprocmask(SIG_SETMASK, &set, NULL);
92866fb9763Sbellard 
92966fb9763Sbellard 	if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax))
93066fb9763Sbellard 		goto badframe;
93166fb9763Sbellard 
93266fb9763Sbellard #if 0
93366fb9763Sbellard 	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
93466fb9763Sbellard 		goto badframe;
93566fb9763Sbellard 	/* It is more difficult to avoid calling this function than to
93666fb9763Sbellard 	   call it and ignore errors.  */
93766fb9763Sbellard 	do_sigaltstack(&st, NULL, regs->esp);
93866fb9763Sbellard #endif
93966fb9763Sbellard 	return eax;
94066fb9763Sbellard 
94166fb9763Sbellard badframe:
94266fb9763Sbellard 	force_sig(TARGET_SIGSEGV);
94366fb9763Sbellard 	return 0;
94466fb9763Sbellard }
94566fb9763Sbellard 
94643fff238Sbellard #elif defined(TARGET_ARM)
94743fff238Sbellard 
94843fff238Sbellard struct target_sigcontext {
94943fff238Sbellard 	target_ulong trap_no;
95043fff238Sbellard 	target_ulong error_code;
95143fff238Sbellard 	target_ulong oldmask;
95243fff238Sbellard 	target_ulong arm_r0;
95343fff238Sbellard 	target_ulong arm_r1;
95443fff238Sbellard 	target_ulong arm_r2;
95543fff238Sbellard 	target_ulong arm_r3;
95643fff238Sbellard 	target_ulong arm_r4;
95743fff238Sbellard 	target_ulong arm_r5;
95843fff238Sbellard 	target_ulong arm_r6;
95943fff238Sbellard 	target_ulong arm_r7;
96043fff238Sbellard 	target_ulong arm_r8;
96143fff238Sbellard 	target_ulong arm_r9;
96243fff238Sbellard 	target_ulong arm_r10;
96343fff238Sbellard 	target_ulong arm_fp;
96443fff238Sbellard 	target_ulong arm_ip;
96543fff238Sbellard 	target_ulong arm_sp;
96643fff238Sbellard 	target_ulong arm_lr;
96743fff238Sbellard 	target_ulong arm_pc;
96843fff238Sbellard 	target_ulong arm_cpsr;
96943fff238Sbellard 	target_ulong fault_address;
97043fff238Sbellard };
97143fff238Sbellard 
97243fff238Sbellard typedef struct target_sigaltstack {
97343fff238Sbellard 	target_ulong ss_sp;
97443fff238Sbellard 	int ss_flags;
97543fff238Sbellard 	target_ulong ss_size;
97643fff238Sbellard } target_stack_t;
97743fff238Sbellard 
97843fff238Sbellard struct target_ucontext {
97943fff238Sbellard     target_ulong uc_flags;
98043fff238Sbellard     target_ulong uc_link;
98143fff238Sbellard     target_stack_t uc_stack;
98243fff238Sbellard     struct target_sigcontext uc_mcontext;
98343fff238Sbellard     target_sigset_t  uc_sigmask;	/* mask last for extensibility */
98443fff238Sbellard };
98543fff238Sbellard 
98643fff238Sbellard struct sigframe
98743fff238Sbellard {
98843fff238Sbellard     struct target_sigcontext sc;
98943fff238Sbellard     target_ulong extramask[TARGET_NSIG_WORDS-1];
99043fff238Sbellard     target_ulong retcode;
99143fff238Sbellard };
99243fff238Sbellard 
99343fff238Sbellard struct rt_sigframe
99443fff238Sbellard {
99543fff238Sbellard     struct target_siginfo *pinfo;
99643fff238Sbellard     void *puc;
99743fff238Sbellard     struct target_siginfo info;
99843fff238Sbellard     struct target_ucontext uc;
99943fff238Sbellard     target_ulong retcode;
100043fff238Sbellard };
100143fff238Sbellard 
100243fff238Sbellard #define TARGET_CONFIG_CPU_32 1
100343fff238Sbellard 
100443fff238Sbellard /*
100543fff238Sbellard  * For ARM syscalls, we encode the syscall number into the instruction.
100643fff238Sbellard  */
100743fff238Sbellard #define SWI_SYS_SIGRETURN	(0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
100843fff238Sbellard #define SWI_SYS_RT_SIGRETURN	(0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
100943fff238Sbellard 
101043fff238Sbellard /*
101143fff238Sbellard  * For Thumb syscalls, we pass the syscall number via r7.  We therefore
101243fff238Sbellard  * need two 16-bit instructions.
101343fff238Sbellard  */
101443fff238Sbellard #define SWI_THUMB_SIGRETURN	(0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
101543fff238Sbellard #define SWI_THUMB_RT_SIGRETURN	(0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
101643fff238Sbellard 
101743fff238Sbellard static const target_ulong retcodes[4] = {
101843fff238Sbellard 	SWI_SYS_SIGRETURN,	SWI_THUMB_SIGRETURN,
101943fff238Sbellard 	SWI_SYS_RT_SIGRETURN,	SWI_THUMB_RT_SIGRETURN
102043fff238Sbellard };
102143fff238Sbellard 
102243fff238Sbellard 
102343fff238Sbellard #define __put_user_error(x,p,e) __put_user(x, p)
102443fff238Sbellard #define __get_user_error(x,p,e) __get_user(x, p)
102543fff238Sbellard 
102643fff238Sbellard static inline int valid_user_regs(CPUState *regs)
102743fff238Sbellard {
102843fff238Sbellard     return 1;
102943fff238Sbellard }
103043fff238Sbellard 
103143fff238Sbellard static int
103243fff238Sbellard setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
103343fff238Sbellard 		 CPUState *env, unsigned long mask)
103443fff238Sbellard {
103543fff238Sbellard 	int err = 0;
103643fff238Sbellard 
103743fff238Sbellard 	__put_user_error(env->regs[0], &sc->arm_r0, err);
103843fff238Sbellard 	__put_user_error(env->regs[1], &sc->arm_r1, err);
103943fff238Sbellard 	__put_user_error(env->regs[2], &sc->arm_r2, err);
104043fff238Sbellard 	__put_user_error(env->regs[3], &sc->arm_r3, err);
104143fff238Sbellard 	__put_user_error(env->regs[4], &sc->arm_r4, err);
104243fff238Sbellard 	__put_user_error(env->regs[5], &sc->arm_r5, err);
104343fff238Sbellard 	__put_user_error(env->regs[6], &sc->arm_r6, err);
104443fff238Sbellard 	__put_user_error(env->regs[7], &sc->arm_r7, err);
104543fff238Sbellard 	__put_user_error(env->regs[8], &sc->arm_r8, err);
104643fff238Sbellard 	__put_user_error(env->regs[9], &sc->arm_r9, err);
104743fff238Sbellard 	__put_user_error(env->regs[10], &sc->arm_r10, err);
104843fff238Sbellard 	__put_user_error(env->regs[11], &sc->arm_fp, err);
104943fff238Sbellard 	__put_user_error(env->regs[12], &sc->arm_ip, err);
105043fff238Sbellard 	__put_user_error(env->regs[13], &sc->arm_sp, err);
105143fff238Sbellard 	__put_user_error(env->regs[14], &sc->arm_lr, err);
105243fff238Sbellard 	__put_user_error(env->regs[15], &sc->arm_pc, err);
105343fff238Sbellard #ifdef TARGET_CONFIG_CPU_32
105443fff238Sbellard 	__put_user_error(env->cpsr, &sc->arm_cpsr, err);
105543fff238Sbellard #endif
105643fff238Sbellard 
105743fff238Sbellard 	__put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err);
105843fff238Sbellard 	__put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err);
105943fff238Sbellard 	__put_user_error(/* current->thread.address */ 0, &sc->fault_address, err);
106043fff238Sbellard 	__put_user_error(mask, &sc->oldmask, err);
106143fff238Sbellard 
106243fff238Sbellard 	return err;
106343fff238Sbellard }
106443fff238Sbellard 
106543fff238Sbellard static inline void *
106643fff238Sbellard get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize)
106743fff238Sbellard {
106843fff238Sbellard 	unsigned long sp = regs->regs[13];
106943fff238Sbellard 
107043fff238Sbellard #if 0
107143fff238Sbellard 	/*
107243fff238Sbellard 	 * This is the X/Open sanctioned signal stack switching.
107343fff238Sbellard 	 */
107443fff238Sbellard 	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
107543fff238Sbellard 		sp = current->sas_ss_sp + current->sas_ss_size;
107643fff238Sbellard #endif
107743fff238Sbellard 	/*
107843fff238Sbellard 	 * ATPCS B01 mandates 8-byte alignment
107943fff238Sbellard 	 */
108043fff238Sbellard 	return (void *)((sp - framesize) & ~7);
108143fff238Sbellard }
108243fff238Sbellard 
108343fff238Sbellard static int
108443fff238Sbellard setup_return(CPUState *env, struct emulated_sigaction *ka,
108543fff238Sbellard 	     target_ulong *rc, void *frame, int usig)
108643fff238Sbellard {
108743fff238Sbellard 	target_ulong handler = (target_ulong)ka->sa._sa_handler;
108843fff238Sbellard 	target_ulong retcode;
108943fff238Sbellard 	int thumb = 0;
109043fff238Sbellard #if defined(TARGET_CONFIG_CPU_32)
109143fff238Sbellard 	target_ulong cpsr = env->cpsr;
109243fff238Sbellard 
109343fff238Sbellard #if 0
109443fff238Sbellard 	/*
109543fff238Sbellard 	 * Maybe we need to deliver a 32-bit signal to a 26-bit task.
109643fff238Sbellard 	 */
109743fff238Sbellard 	if (ka->sa.sa_flags & SA_THIRTYTWO)
109843fff238Sbellard 		cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
109943fff238Sbellard 
110043fff238Sbellard #ifdef CONFIG_ARM_THUMB
110143fff238Sbellard 	if (elf_hwcap & HWCAP_THUMB) {
110243fff238Sbellard 		/*
110343fff238Sbellard 		 * The LSB of the handler determines if we're going to
110443fff238Sbellard 		 * be using THUMB or ARM mode for this signal handler.
110543fff238Sbellard 		 */
110643fff238Sbellard 		thumb = handler & 1;
110743fff238Sbellard 
110843fff238Sbellard 		if (thumb)
110943fff238Sbellard 			cpsr |= T_BIT;
111043fff238Sbellard 		else
111143fff238Sbellard 			cpsr &= ~T_BIT;
111243fff238Sbellard 	}
111343fff238Sbellard #endif
111443fff238Sbellard #endif
111543fff238Sbellard #endif /* TARGET_CONFIG_CPU_32 */
111643fff238Sbellard 
111743fff238Sbellard 	if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
111843fff238Sbellard 		retcode = (target_ulong)ka->sa.sa_restorer;
111943fff238Sbellard 	} else {
112043fff238Sbellard 		unsigned int idx = thumb;
112143fff238Sbellard 
112243fff238Sbellard 		if (ka->sa.sa_flags & TARGET_SA_SIGINFO)
112343fff238Sbellard 			idx += 2;
112443fff238Sbellard 
112543fff238Sbellard 		if (__put_user(retcodes[idx], rc))
112643fff238Sbellard 			return 1;
112743fff238Sbellard #if 0
112843fff238Sbellard 		flush_icache_range((target_ulong)rc,
112943fff238Sbellard 				   (target_ulong)(rc + 1));
113043fff238Sbellard #endif
113143fff238Sbellard 		retcode = ((target_ulong)rc) + thumb;
113243fff238Sbellard 	}
113343fff238Sbellard 
113443fff238Sbellard 	env->regs[0] = usig;
113543fff238Sbellard 	env->regs[13] = (target_ulong)frame;
113643fff238Sbellard 	env->regs[14] = retcode;
113743fff238Sbellard 	env->regs[15] = handler & (thumb ? ~1 : ~3);
113843fff238Sbellard 
113943fff238Sbellard #ifdef TARGET_CONFIG_CPU_32
114043fff238Sbellard 	env->cpsr = cpsr;
114143fff238Sbellard #endif
114243fff238Sbellard 
114343fff238Sbellard 	return 0;
114443fff238Sbellard }
114543fff238Sbellard 
114643fff238Sbellard static void setup_frame(int usig, struct emulated_sigaction *ka,
114743fff238Sbellard 			target_sigset_t *set, CPUState *regs)
114843fff238Sbellard {
114943fff238Sbellard 	struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
115043fff238Sbellard 	int err = 0;
115143fff238Sbellard 
115243fff238Sbellard 	err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
115343fff238Sbellard 
115443fff238Sbellard 	if (TARGET_NSIG_WORDS > 1) {
115543fff238Sbellard 		err |= __copy_to_user(frame->extramask, &set->sig[1],
115643fff238Sbellard 				      sizeof(frame->extramask));
115743fff238Sbellard 	}
115843fff238Sbellard 
115943fff238Sbellard 	if (err == 0)
116043fff238Sbellard             err = setup_return(regs, ka, &frame->retcode, frame, usig);
116143fff238Sbellard         //	return err;
116243fff238Sbellard }
116343fff238Sbellard 
116443fff238Sbellard static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
116543fff238Sbellard                            target_siginfo_t *info,
116643fff238Sbellard 			   target_sigset_t *set, CPUState *env)
116743fff238Sbellard {
116843fff238Sbellard 	struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
116943fff238Sbellard 	int err = 0;
117043fff238Sbellard 
117143fff238Sbellard #if 0
117243fff238Sbellard 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
117343fff238Sbellard             return 1;
117443fff238Sbellard #endif
117543fff238Sbellard 	__put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err);
117643fff238Sbellard 	__put_user_error(&frame->uc, (target_ulong *)&frame->puc, err);
117743fff238Sbellard 	err |= copy_siginfo_to_user(&frame->info, info);
117843fff238Sbellard 
117943fff238Sbellard 	/* Clear all the bits of the ucontext we don't use.  */
118043fff238Sbellard 	err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
118143fff238Sbellard 
118243fff238Sbellard 	err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
118343fff238Sbellard 				env, set->sig[0]);
118443fff238Sbellard 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
118543fff238Sbellard 
118643fff238Sbellard 	if (err == 0)
118743fff238Sbellard 		err = setup_return(env, ka, &frame->retcode, frame, usig);
118843fff238Sbellard 
118943fff238Sbellard 	if (err == 0) {
119043fff238Sbellard 		/*
119143fff238Sbellard 		 * For realtime signals we must also set the second and third
119243fff238Sbellard 		 * arguments for the signal handler.
119343fff238Sbellard 		 *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
119443fff238Sbellard 		 */
119543fff238Sbellard             env->regs[1] = (target_ulong)frame->pinfo;
119643fff238Sbellard             env->regs[2] = (target_ulong)frame->puc;
119743fff238Sbellard 	}
119843fff238Sbellard 
119943fff238Sbellard         //	return err;
120043fff238Sbellard }
120143fff238Sbellard 
120243fff238Sbellard static int
120343fff238Sbellard restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
120443fff238Sbellard {
120543fff238Sbellard 	int err = 0;
120643fff238Sbellard 
120743fff238Sbellard 	__get_user_error(env->regs[0], &sc->arm_r0, err);
120843fff238Sbellard 	__get_user_error(env->regs[1], &sc->arm_r1, err);
120943fff238Sbellard 	__get_user_error(env->regs[2], &sc->arm_r2, err);
121043fff238Sbellard 	__get_user_error(env->regs[3], &sc->arm_r3, err);
121143fff238Sbellard 	__get_user_error(env->regs[4], &sc->arm_r4, err);
121243fff238Sbellard 	__get_user_error(env->regs[5], &sc->arm_r5, err);
121343fff238Sbellard 	__get_user_error(env->regs[6], &sc->arm_r6, err);
121443fff238Sbellard 	__get_user_error(env->regs[7], &sc->arm_r7, err);
121543fff238Sbellard 	__get_user_error(env->regs[8], &sc->arm_r8, err);
121643fff238Sbellard 	__get_user_error(env->regs[9], &sc->arm_r9, err);
121743fff238Sbellard 	__get_user_error(env->regs[10], &sc->arm_r10, err);
121843fff238Sbellard 	__get_user_error(env->regs[11], &sc->arm_fp, err);
121943fff238Sbellard 	__get_user_error(env->regs[12], &sc->arm_ip, err);
122043fff238Sbellard 	__get_user_error(env->regs[13], &sc->arm_sp, err);
122143fff238Sbellard 	__get_user_error(env->regs[14], &sc->arm_lr, err);
122243fff238Sbellard 	__get_user_error(env->regs[15], &sc->arm_pc, err);
122343fff238Sbellard #ifdef TARGET_CONFIG_CPU_32
122443fff238Sbellard 	__get_user_error(env->cpsr, &sc->arm_cpsr, err);
122543fff238Sbellard #endif
122643fff238Sbellard 
122743fff238Sbellard 	err |= !valid_user_regs(env);
122843fff238Sbellard 
122943fff238Sbellard 	return err;
123043fff238Sbellard }
123143fff238Sbellard 
123243fff238Sbellard long do_sigreturn(CPUState *env)
123343fff238Sbellard {
123443fff238Sbellard 	struct sigframe *frame;
123543fff238Sbellard 	target_sigset_t set;
123643fff238Sbellard         sigset_t host_set;
123743fff238Sbellard 
123843fff238Sbellard 	/*
123943fff238Sbellard 	 * Since we stacked the signal on a 64-bit boundary,
124043fff238Sbellard 	 * then 'sp' should be word aligned here.  If it's
124143fff238Sbellard 	 * not, then the user is trying to mess with us.
124243fff238Sbellard 	 */
124343fff238Sbellard 	if (env->regs[13] & 7)
124443fff238Sbellard 		goto badframe;
124543fff238Sbellard 
124643fff238Sbellard 	frame = (struct sigframe *)env->regs[13];
124743fff238Sbellard 
124843fff238Sbellard #if 0
124943fff238Sbellard 	if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
125043fff238Sbellard 		goto badframe;
125143fff238Sbellard #endif
125243fff238Sbellard 	if (__get_user(set.sig[0], &frame->sc.oldmask)
125343fff238Sbellard 	    || (TARGET_NSIG_WORDS > 1
125443fff238Sbellard 	        && __copy_from_user(&set.sig[1], &frame->extramask,
125543fff238Sbellard 				    sizeof(frame->extramask))))
125643fff238Sbellard 		goto badframe;
125743fff238Sbellard 
125843fff238Sbellard         target_to_host_sigset(&host_set, &set);
125943fff238Sbellard         sigprocmask(SIG_SETMASK, &host_set, NULL);
126043fff238Sbellard 
126143fff238Sbellard 	if (restore_sigcontext(env, &frame->sc))
126243fff238Sbellard 		goto badframe;
126343fff238Sbellard 
126443fff238Sbellard #if 0
126543fff238Sbellard 	/* Send SIGTRAP if we're single-stepping */
126643fff238Sbellard 	if (ptrace_cancel_bpt(current))
126743fff238Sbellard 		send_sig(SIGTRAP, current, 1);
126843fff238Sbellard #endif
126943fff238Sbellard 	return env->regs[0];
127043fff238Sbellard 
127143fff238Sbellard badframe:
127243fff238Sbellard         force_sig(SIGSEGV /* , current */);
127343fff238Sbellard 	return 0;
127443fff238Sbellard }
127543fff238Sbellard 
127643fff238Sbellard long do_rt_sigreturn(CPUState *env)
127743fff238Sbellard {
127843fff238Sbellard 	struct rt_sigframe *frame;
127943fff238Sbellard 	target_sigset_t set;
128043fff238Sbellard         sigset_t host_set;
128143fff238Sbellard 
128243fff238Sbellard 	/*
128343fff238Sbellard 	 * Since we stacked the signal on a 64-bit boundary,
128443fff238Sbellard 	 * then 'sp' should be word aligned here.  If it's
128543fff238Sbellard 	 * not, then the user is trying to mess with us.
128643fff238Sbellard 	 */
128743fff238Sbellard 	if (env->regs[13] & 7)
128843fff238Sbellard 		goto badframe;
128943fff238Sbellard 
129043fff238Sbellard 	frame = (struct rt_sigframe *)env->regs[13];
129143fff238Sbellard 
129243fff238Sbellard #if 0
129343fff238Sbellard 	if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
129443fff238Sbellard 		goto badframe;
129543fff238Sbellard #endif
129643fff238Sbellard 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
129743fff238Sbellard 		goto badframe;
129843fff238Sbellard 
129943fff238Sbellard         target_to_host_sigset(&host_set, &set);
130043fff238Sbellard         sigprocmask(SIG_SETMASK, &host_set, NULL);
130143fff238Sbellard 
130243fff238Sbellard 	if (restore_sigcontext(env, &frame->uc.uc_mcontext))
130343fff238Sbellard 		goto badframe;
130443fff238Sbellard 
130543fff238Sbellard #if 0
130643fff238Sbellard 	/* Send SIGTRAP if we're single-stepping */
130743fff238Sbellard 	if (ptrace_cancel_bpt(current))
130843fff238Sbellard 		send_sig(SIGTRAP, current, 1);
130943fff238Sbellard #endif
131043fff238Sbellard 	return env->regs[0];
131143fff238Sbellard 
131243fff238Sbellard badframe:
131343fff238Sbellard         force_sig(SIGSEGV /* , current */);
131443fff238Sbellard 	return 0;
131543fff238Sbellard }
131643fff238Sbellard 
1317b346ff46Sbellard #else
1318b346ff46Sbellard 
1319b346ff46Sbellard static void setup_frame(int sig, struct emulated_sigaction *ka,
1320b346ff46Sbellard 			target_sigset_t *set, CPUState *env)
1321b346ff46Sbellard {
1322b346ff46Sbellard     fprintf(stderr, "setup_frame: not implemented\n");
1323b346ff46Sbellard }
1324b346ff46Sbellard 
1325b346ff46Sbellard static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
1326b346ff46Sbellard                            target_siginfo_t *info,
1327b346ff46Sbellard 			   target_sigset_t *set, CPUState *env)
1328b346ff46Sbellard {
1329b346ff46Sbellard     fprintf(stderr, "setup_rt_frame: not implemented\n");
1330b346ff46Sbellard }
1331b346ff46Sbellard 
1332b346ff46Sbellard long do_sigreturn(CPUState *env)
1333b346ff46Sbellard {
1334b346ff46Sbellard     fprintf(stderr, "do_sigreturn: not implemented\n");
1335b346ff46Sbellard     return -ENOSYS;
1336b346ff46Sbellard }
1337b346ff46Sbellard 
1338b346ff46Sbellard long do_rt_sigreturn(CPUState *env)
1339b346ff46Sbellard {
1340b346ff46Sbellard     fprintf(stderr, "do_rt_sigreturn: not implemented\n");
1341b346ff46Sbellard     return -ENOSYS;
1342b346ff46Sbellard }
1343b346ff46Sbellard 
134466fb9763Sbellard #endif
134566fb9763Sbellard 
134666fb9763Sbellard void process_pending_signals(void *cpu_env)
134766fb9763Sbellard {
134866fb9763Sbellard     int sig;
134966fb9763Sbellard     target_ulong handler;
13509de5e440Sbellard     sigset_t set, old_set;
13519de5e440Sbellard     target_sigset_t target_old_set;
135266fb9763Sbellard     struct emulated_sigaction *k;
135366fb9763Sbellard     struct sigqueue *q;
135431e31b8aSbellard 
135531e31b8aSbellard     if (!signal_pending)
135631e31b8aSbellard         return;
135731e31b8aSbellard 
135866fb9763Sbellard     k = sigact_table;
135966fb9763Sbellard     for(sig = 1; sig <= TARGET_NSIG; sig++) {
136066fb9763Sbellard         if (k->pending)
136131e31b8aSbellard             goto handle_signal;
136266fb9763Sbellard         k++;
136331e31b8aSbellard     }
136431e31b8aSbellard     /* if no signal is pending, just return */
136531e31b8aSbellard     signal_pending = 0;
136631e31b8aSbellard     return;
136766fb9763Sbellard 
136831e31b8aSbellard  handle_signal:
136966fb9763Sbellard #ifdef DEBUG_SIGNAL
1370bc8a22ccSbellard     fprintf(stderr, "qemu: process signal %d\n", sig);
137166fb9763Sbellard #endif
137266fb9763Sbellard     /* dequeue signal */
137366fb9763Sbellard     q = k->first;
137466fb9763Sbellard     k->first = q->next;
137566fb9763Sbellard     if (!k->first)
137666fb9763Sbellard         k->pending = 0;
137766fb9763Sbellard 
137866fb9763Sbellard     handler = k->sa._sa_handler;
137966fb9763Sbellard     if (handler == TARGET_SIG_DFL) {
138066fb9763Sbellard         /* default handler : ignore some signal. The other are fatal */
138166fb9763Sbellard         if (sig != TARGET_SIGCHLD &&
138266fb9763Sbellard             sig != TARGET_SIGURG &&
138366fb9763Sbellard             sig != TARGET_SIGWINCH) {
138466fb9763Sbellard             force_sig(sig);
138566fb9763Sbellard         }
138666fb9763Sbellard     } else if (handler == TARGET_SIG_IGN) {
138766fb9763Sbellard         /* ignore sig */
138866fb9763Sbellard     } else if (handler == TARGET_SIG_ERR) {
138966fb9763Sbellard         force_sig(sig);
139066fb9763Sbellard     } else {
13919de5e440Sbellard         /* compute the blocked signals during the handler execution */
13929de5e440Sbellard         target_to_host_sigset(&set, &k->sa.sa_mask);
13939de5e440Sbellard         /* SA_NODEFER indicates that the current signal should not be
13949de5e440Sbellard            blocked during the handler */
13959de5e440Sbellard         if (!(k->sa.sa_flags & TARGET_SA_NODEFER))
13969de5e440Sbellard             sigaddset(&set, target_to_host_signal(sig));
13979de5e440Sbellard 
13989de5e440Sbellard         /* block signals in the handler using Linux */
13999de5e440Sbellard         sigprocmask(SIG_BLOCK, &set, &old_set);
14009de5e440Sbellard         /* save the previous blocked signal state to restore it at the
14019de5e440Sbellard            end of the signal execution (see do_sigreturn) */
14029de5e440Sbellard         host_to_target_sigset(&target_old_set, &old_set);
14039de5e440Sbellard 
1404bc8a22ccSbellard         /* if the CPU is in VM86 mode, we restore the 32 bit values */
1405bc8a22ccSbellard #ifdef TARGET_I386
1406bc8a22ccSbellard         {
1407bc8a22ccSbellard             CPUX86State *env = cpu_env;
1408bc8a22ccSbellard             if (env->eflags & VM_MASK)
1409bc8a22ccSbellard                 save_v86_state(env);
1410bc8a22ccSbellard         }
1411bc8a22ccSbellard #endif
14129de5e440Sbellard         /* prepare the stack frame of the virtual CPU */
141366fb9763Sbellard         if (k->sa.sa_flags & TARGET_SA_SIGINFO)
14149de5e440Sbellard             setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env);
141566fb9763Sbellard         else
14169de5e440Sbellard             setup_frame(sig, k, &target_old_set, cpu_env);
141766fb9763Sbellard 	if (k->sa.sa_flags & TARGET_SA_RESETHAND)
141866fb9763Sbellard             k->sa._sa_handler = TARGET_SIG_DFL;
141966fb9763Sbellard     }
142066fb9763Sbellard     if (q != &k->info)
142166fb9763Sbellard         free_sigqueue(q);
142231e31b8aSbellard }
142331e31b8aSbellard 
142431e31b8aSbellard 
1425