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(¤t->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" (®s)); 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