blob: af40238b2bf91d568b14bf59c0e0aefde3ba733f [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20#include <stdlib.h>
21#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000022#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000023#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000024#include <unistd.h>
bellard31e31b82003-02-18 22:55:36 +000025#include <signal.h>
bellard66fb9762003-03-23 01:06:05 +000026#include <errno.h>
bellard31e31b82003-02-18 22:55:36 +000027#include <sys/ucontext.h>
28
bellard3ef693a2003-03-23 20:17:16 +000029#include "qemu.h"
blueswir1992f48a2007-10-14 16:27:31 +000030#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000031
32//#define DEBUG_SIGNAL
33
thsa04e1342007-09-27 13:57:58 +000034struct target_sigaltstack target_sigaltstack_used = {
35 .ss_sp = 0,
36 .ss_size = 0,
37 .ss_flags = TARGET_SS_DISABLE,
38};
39
pbrook624f7972008-05-31 16:11:38 +000040static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000041
ths5fafdf22007-09-16 21:08:06 +000042static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000043 void *puc);
44
bellard9e5f5282003-07-13 17:33:54 +000045static uint8_t host_to_target_signal_table[65] = {
46 [SIGHUP] = TARGET_SIGHUP,
47 [SIGINT] = TARGET_SIGINT,
48 [SIGQUIT] = TARGET_SIGQUIT,
49 [SIGILL] = TARGET_SIGILL,
50 [SIGTRAP] = TARGET_SIGTRAP,
51 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000052/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000053 [SIGBUS] = TARGET_SIGBUS,
54 [SIGFPE] = TARGET_SIGFPE,
55 [SIGKILL] = TARGET_SIGKILL,
56 [SIGUSR1] = TARGET_SIGUSR1,
57 [SIGSEGV] = TARGET_SIGSEGV,
58 [SIGUSR2] = TARGET_SIGUSR2,
59 [SIGPIPE] = TARGET_SIGPIPE,
60 [SIGALRM] = TARGET_SIGALRM,
61 [SIGTERM] = TARGET_SIGTERM,
62#ifdef SIGSTKFLT
63 [SIGSTKFLT] = TARGET_SIGSTKFLT,
64#endif
65 [SIGCHLD] = TARGET_SIGCHLD,
66 [SIGCONT] = TARGET_SIGCONT,
67 [SIGSTOP] = TARGET_SIGSTOP,
68 [SIGTSTP] = TARGET_SIGTSTP,
69 [SIGTTIN] = TARGET_SIGTTIN,
70 [SIGTTOU] = TARGET_SIGTTOU,
71 [SIGURG] = TARGET_SIGURG,
72 [SIGXCPU] = TARGET_SIGXCPU,
73 [SIGXFSZ] = TARGET_SIGXFSZ,
74 [SIGVTALRM] = TARGET_SIGVTALRM,
75 [SIGPROF] = TARGET_SIGPROF,
76 [SIGWINCH] = TARGET_SIGWINCH,
77 [SIGIO] = TARGET_SIGIO,
78 [SIGPWR] = TARGET_SIGPWR,
79 [SIGSYS] = TARGET_SIGSYS,
80 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000081 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
82 host libpthread signals. This assumes noone actually uses SIGRTMAX :-/
83 To fix this properly we need to do manual signal delivery multiplexed
84 over a single host signal. */
85 [__SIGRTMIN] = __SIGRTMAX,
86 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000087};
88static uint8_t target_to_host_signal_table[65];
89
thsa04e1342007-09-27 13:57:58 +000090static inline int on_sig_stack(unsigned long sp)
91{
92 return (sp - target_sigaltstack_used.ss_sp
93 < target_sigaltstack_used.ss_size);
94}
95
96static inline int sas_ss_flags(unsigned long sp)
97{
98 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
99 : on_sig_stack(sp) ? SS_ONSTACK : 0);
100}
101
bellard31e31b82003-02-18 22:55:36 +0000102static inline int host_to_target_signal(int sig)
103{
pbrook4cb05962008-05-30 18:05:19 +0000104 if (sig > 64)
105 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000106 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000107}
108
pbrook4cb05962008-05-30 18:05:19 +0000109int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000110{
pbrook4cb05962008-05-30 18:05:19 +0000111 if (sig > 64)
112 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000113 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000114}
115
pbrookf5545b52008-05-30 22:37:07 +0000116static inline void target_sigemptyset(target_sigset_t *set)
117{
118 memset(set, 0, sizeof(*set));
119}
120
121static inline void target_sigaddset(target_sigset_t *set, int signum)
122{
123 signum--;
124 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
125 set->sig[signum / TARGET_NSIG_BPW] |= mask;
126}
127
128static inline int target_sigismember(const target_sigset_t *set, int signum)
129{
130 signum--;
131 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
132 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
133}
134
ths5fafdf22007-09-16 21:08:06 +0000135static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000136 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000137{
138 int i;
pbrookf5545b52008-05-30 22:37:07 +0000139 target_sigemptyset(d);
140 for (i = 1; i <= TARGET_NSIG; i++) {
141 if (sigismember(s, i)) {
142 target_sigaddset(d, host_to_target_signal(i));
143 }
bellard9e5f5282003-07-13 17:33:54 +0000144 }
bellard66fb9762003-03-23 01:06:05 +0000145}
146
bellard92319442004-06-19 16:58:13 +0000147void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
148{
149 target_sigset_t d1;
150 int i;
151
152 host_to_target_sigset_internal(&d1, s);
153 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000154 d->sig[i] = tswapl(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000155}
156
157void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000158{
159 int i;
pbrookf5545b52008-05-30 22:37:07 +0000160 sigemptyset(d);
161 for (i = 1; i <= TARGET_NSIG; i++) {
162 if (target_sigismember(s, i)) {
163 sigaddset(d, target_to_host_signal(i));
164 }
165 }
bellard66fb9762003-03-23 01:06:05 +0000166}
167
bellard92319442004-06-19 16:58:13 +0000168void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
169{
170 target_sigset_t s1;
171 int i;
172
173 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000174 s1.sig[i] = tswapl(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000175 target_to_host_sigset_internal(d, &s1);
176}
ths3b46e622007-09-17 08:09:54 +0000177
blueswir1992f48a2007-10-14 16:27:31 +0000178void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000179 const sigset_t *sigset)
180{
bellard9e5f5282003-07-13 17:33:54 +0000181 target_sigset_t d;
182 host_to_target_sigset(&d, sigset);
183 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000184}
185
ths5fafdf22007-09-16 21:08:06 +0000186void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000187 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000188{
bellard9e5f5282003-07-13 17:33:54 +0000189 target_sigset_t d;
190 int i;
191
192 d.sig[0] = *old_sigset;
193 for(i = 1;i < TARGET_NSIG_WORDS; i++)
194 d.sig[i] = 0;
195 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000196}
197
bellard9de5e442003-03-23 16:49:39 +0000198/* siginfo conversion */
199
ths5fafdf22007-09-16 21:08:06 +0000200static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000201 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000202{
bellard9de5e442003-03-23 16:49:39 +0000203 int sig;
204 sig = host_to_target_signal(info->si_signo);
205 tinfo->si_signo = sig;
206 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000207 tinfo->si_code = info->si_code;
ths5fafdf22007-09-16 21:08:06 +0000208 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000209 sig == SIGBUS || sig == SIGTRAP) {
bellard9de5e442003-03-23 16:49:39 +0000210 /* should never come here, but who knows. The information for
211 the target is irrelevant */
212 tinfo->_sifields._sigfault._addr = 0;
ths7f7f7c82007-07-12 11:02:46 +0000213 } else if (sig == SIGIO) {
214 tinfo->_sifields._sigpoll._fd = info->si_fd;
bellard9de5e442003-03-23 16:49:39 +0000215 } else if (sig >= TARGET_SIGRTMIN) {
216 tinfo->_sifields._rt._pid = info->si_pid;
217 tinfo->_sifields._rt._uid = info->si_uid;
218 /* XXX: potential problem if 64 bit */
ths5fafdf22007-09-16 21:08:06 +0000219 tinfo->_sifields._rt._sigval.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000220 (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000221 }
bellard66fb9762003-03-23 01:06:05 +0000222}
223
ths5fafdf22007-09-16 21:08:06 +0000224static void tswap_siginfo(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000225 const target_siginfo_t *info)
226{
227 int sig;
228 sig = info->si_signo;
229 tinfo->si_signo = tswap32(sig);
230 tinfo->si_errno = tswap32(info->si_errno);
231 tinfo->si_code = tswap32(info->si_code);
ths5fafdf22007-09-16 21:08:06 +0000232 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000233 sig == SIGBUS || sig == SIGTRAP) {
ths5fafdf22007-09-16 21:08:06 +0000234 tinfo->_sifields._sigfault._addr =
bellard9de5e442003-03-23 16:49:39 +0000235 tswapl(info->_sifields._sigfault._addr);
ths7f7f7c82007-07-12 11:02:46 +0000236 } else if (sig == SIGIO) {
237 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
bellard9de5e442003-03-23 16:49:39 +0000238 } else if (sig >= TARGET_SIGRTMIN) {
239 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
240 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000241 tinfo->_sifields._rt._sigval.sival_ptr =
bellard9de5e442003-03-23 16:49:39 +0000242 tswapl(info->_sifields._rt._sigval.sival_ptr);
243 }
244}
245
246
247void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
248{
249 host_to_target_siginfo_noswap(tinfo, info);
250 tswap_siginfo(tinfo, tinfo);
251}
252
253/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000254/* XXX: find a solution for 64 bit (additional malloced data is needed) */
bellard9de5e442003-03-23 16:49:39 +0000255void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000256{
257 info->si_signo = tswap32(tinfo->si_signo);
258 info->si_errno = tswap32(tinfo->si_errno);
259 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000260 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
261 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000262 info->si_value.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000263 (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000264}
265
bellard31e31b82003-02-18 22:55:36 +0000266void signal_init(void)
267{
268 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000269 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000270 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000271 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000272
bellard9e5f5282003-07-13 17:33:54 +0000273 /* generate signal conversion tables */
274 for(i = 1; i <= 64; i++) {
275 if (host_to_target_signal_table[i] == 0)
276 host_to_target_signal_table[i] = i;
277 }
278 for(i = 1; i <= 64; i++) {
279 j = host_to_target_signal_table[i];
280 target_to_host_signal_table[j] = i;
281 }
ths3b46e622007-09-17 08:09:54 +0000282
bellard9de5e442003-03-23 16:49:39 +0000283 /* set all host signal handlers. ALL signals are blocked during
284 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000285 memset(sigact_table, 0, sizeof(sigact_table));
286
bellard9de5e442003-03-23 16:49:39 +0000287 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000288 act.sa_flags = SA_SIGINFO;
289 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000290 for(i = 1; i <= TARGET_NSIG; i++) {
291 host_sig = target_to_host_signal(i);
292 sigaction(host_sig, NULL, &oact);
293 if (oact.sa_sigaction == (void *)SIG_IGN) {
294 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
295 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
296 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
297 }
298 /* If there's already a handler installed then something has
299 gone horribly wrong, so don't even try to handle that case. */
300 /* Install some handlers for our own use. */
301 if (host_sig == SIGSEGV || host_sig == SIGBUS) {
302 sigaction(host_sig, &act, NULL);
303 }
bellard31e31b82003-02-18 22:55:36 +0000304 }
bellard31e31b82003-02-18 22:55:36 +0000305}
306
bellard66fb9762003-03-23 01:06:05 +0000307/* signal queue handling */
308
pbrook624f7972008-05-31 16:11:38 +0000309static inline struct sigqueue *alloc_sigqueue(CPUState *env)
bellard66fb9762003-03-23 01:06:05 +0000310{
pbrook624f7972008-05-31 16:11:38 +0000311 TaskState *ts = env->opaque;
312 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000313 if (!q)
314 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000315 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000316 return q;
317}
318
pbrook624f7972008-05-31 16:11:38 +0000319static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000320{
pbrook624f7972008-05-31 16:11:38 +0000321 TaskState *ts = env->opaque;
322 q->next = ts->first_free;
323 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000324}
325
bellard9de5e442003-03-23 16:49:39 +0000326/* abort execution with signal */
327void __attribute((noreturn)) force_sig(int sig)
bellard66fb9762003-03-23 01:06:05 +0000328{
329 int host_sig;
bellard66fb9762003-03-23 01:06:05 +0000330 host_sig = target_to_host_signal(sig);
ths5fafdf22007-09-16 21:08:06 +0000331 fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
bellard66fb9762003-03-23 01:06:05 +0000332 sig, strsignal(host_sig));
bellard9de5e442003-03-23 16:49:39 +0000333#if 1
bellard66fb9762003-03-23 01:06:05 +0000334 _exit(-host_sig);
bellard9de5e442003-03-23 16:49:39 +0000335#else
336 {
337 struct sigaction act;
338 sigemptyset(&act.sa_mask);
339 act.sa_flags = SA_SIGINFO;
340 act.sa_sigaction = SIG_DFL;
341 sigaction(SIGABRT, &act, NULL);
342 abort();
343 }
344#endif
bellard66fb9762003-03-23 01:06:05 +0000345}
346
bellard9de5e442003-03-23 16:49:39 +0000347/* queue a signal so that it will be send to the virtual CPU as soon
348 as possible */
pbrook624f7972008-05-31 16:11:38 +0000349int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000350{
pbrook624f7972008-05-31 16:11:38 +0000351 TaskState *ts = env->opaque;
352 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000353 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000354 abi_ulong handler;
bellard66fb9762003-03-23 01:06:05 +0000355
bellard9de5e442003-03-23 16:49:39 +0000356#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000357 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000358 sig);
bellard66fb9762003-03-23 01:06:05 +0000359#endif
pbrook624f7972008-05-31 16:11:38 +0000360 k = &ts->sigtab[sig - 1];
361 handler = sigact_table[sig - 1]._sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000362 if (handler == TARGET_SIG_DFL) {
363 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000364 if (sig != TARGET_SIGCHLD &&
365 sig != TARGET_SIGURG &&
bellard66fb9762003-03-23 01:06:05 +0000366 sig != TARGET_SIGWINCH) {
367 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000368 } else {
369 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000370 }
371 } else if (handler == TARGET_SIG_IGN) {
372 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000373 return 0;
bellard66fb9762003-03-23 01:06:05 +0000374 } else if (handler == TARGET_SIG_ERR) {
375 force_sig(sig);
376 } else {
bellard9de5e442003-03-23 16:49:39 +0000377 pq = &k->first;
378 if (sig < TARGET_SIGRTMIN) {
379 /* if non real time signal, we queue exactly one signal */
380 if (!k->pending)
381 q = &k->info;
382 else
383 return 0;
384 } else {
385 if (!k->pending) {
386 /* first signal */
387 q = &k->info;
388 } else {
pbrook624f7972008-05-31 16:11:38 +0000389 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000390 if (!q)
391 return -EAGAIN;
392 while (*pq != NULL)
393 pq = &(*pq)->next;
394 }
395 }
396 *pq = q;
397 q->info = *info;
398 q->next = NULL;
399 k->pending = 1;
400 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000401 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000402 return 1; /* indicates that the signal was queued */
403 }
404}
405
ths5fafdf22007-09-16 21:08:06 +0000406static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000407 void *puc)
408{
409 int sig;
410 target_siginfo_t tinfo;
411
412 /* the CPU emulator uses some host signals to detect exceptions,
413 we we forward to it some signals */
bellardec6338b2007-11-08 14:25:03 +0000414 if (host_signum == SIGSEGV || host_signum == SIGBUS) {
bellardb346ff42003-06-15 20:05:50 +0000415 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000416 return;
417 }
418
419 /* get target signal number */
420 sig = host_to_target_signal(host_signum);
421 if (sig < 1 || sig > TARGET_NSIG)
422 return;
423#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000424 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000425#endif
426 host_to_target_siginfo_noswap(&tinfo, info);
pbrookd5975362008-06-07 20:50:51 +0000427 if (queue_signal(thread_env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000428 /* interrupt the virtual CPU as soon as possible */
pbrookd5975362008-06-07 20:50:51 +0000429 cpu_interrupt(thread_env, CPU_INTERRUPT_EXIT);
bellard66fb9762003-03-23 01:06:05 +0000430 }
bellard31e31b82003-02-18 22:55:36 +0000431}
432
ths0da46a62007-10-20 20:23:07 +0000433/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000434/* compare linux/kernel/signal.c:do_sigaltstack() */
435abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000436{
437 int ret;
438 struct target_sigaltstack oss;
439
440 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000441 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000442 {
443 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
444 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
445 __put_user(sas_ss_flags(sp), &oss.ss_flags);
446 }
447
bellard579a97f2007-11-11 14:26:47 +0000448 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000449 {
bellard579a97f2007-11-11 14:26:47 +0000450 struct target_sigaltstack *uss;
451 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000452
ths0da46a62007-10-20 20:23:07 +0000453 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000454 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000455 || __get_user(ss.ss_sp, &uss->ss_sp)
456 || __get_user(ss.ss_size, &uss->ss_size)
457 || __get_user(ss.ss_flags, &uss->ss_flags))
458 goto out;
bellard579a97f2007-11-11 14:26:47 +0000459 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000460
ths0da46a62007-10-20 20:23:07 +0000461 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000462 if (on_sig_stack(sp))
463 goto out;
464
ths0da46a62007-10-20 20:23:07 +0000465 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000466 if (ss.ss_flags != TARGET_SS_DISABLE
467 && ss.ss_flags != TARGET_SS_ONSTACK
468 && ss.ss_flags != 0)
469 goto out;
470
471 if (ss.ss_flags == TARGET_SS_DISABLE) {
472 ss.ss_size = 0;
473 ss.ss_sp = 0;
474 } else {
ths0da46a62007-10-20 20:23:07 +0000475 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000476 if (ss.ss_size < MINSIGSTKSZ)
477 goto out;
478 }
479
480 target_sigaltstack_used.ss_sp = ss.ss_sp;
481 target_sigaltstack_used.ss_size = ss.ss_size;
482 }
483
bellard579a97f2007-11-11 14:26:47 +0000484 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000485 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000486 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000487 goto out;
thsa04e1342007-09-27 13:57:58 +0000488 }
489
490 ret = 0;
491out:
492 return ret;
493}
494
ths0da46a62007-10-20 20:23:07 +0000495/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000496int do_sigaction(int sig, const struct target_sigaction *act,
497 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000498{
pbrook624f7972008-05-31 16:11:38 +0000499 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000500 struct sigaction act1;
501 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000502 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000503
ths0aeaa8c2007-03-31 19:29:06 +0000504 if (sig < 1 || sig > TARGET_NSIG || sig == SIGKILL || sig == SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000505 return -EINVAL;
506 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000507#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000508 fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
bellard66fb9762003-03-23 01:06:05 +0000509 sig, (int)act, (int)oact);
510#endif
511 if (oact) {
pbrook624f7972008-05-31 16:11:38 +0000512 oact->_sa_handler = tswapl(k->_sa_handler);
513 oact->sa_flags = tswapl(k->sa_flags);
ths388bb212007-05-13 13:58:00 +0000514#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000515 oact->sa_restorer = tswapl(k->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000516#endif
pbrook624f7972008-05-31 16:11:38 +0000517 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000518 }
519 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000520 /* FIXME: This is not threadsafe. */
521 k->_sa_handler = tswapl(act->_sa_handler);
522 k->sa_flags = tswapl(act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000523#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000524 k->sa_restorer = tswapl(act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000525#endif
pbrook624f7972008-05-31 16:11:38 +0000526 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000527
528 /* we update the host linux signal state */
529 host_sig = target_to_host_signal(sig);
530 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
531 sigfillset(&act1.sa_mask);
532 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000533 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000534 act1.sa_flags |= SA_RESTART;
535 /* NOTE: it is important to update the host kernel signal
536 ignore state to avoid getting unexpected interrupted
537 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000538 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000539 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000540 } else if (k->_sa_handler == TARGET_SIG_DFL) {
bellard773b93e2004-01-04 17:15:59 +0000541 act1.sa_sigaction = (void *)SIG_DFL;
542 } else {
543 act1.sa_sigaction = host_signal_handler;
544 }
ths0da46a62007-10-20 20:23:07 +0000545 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000546 }
bellard66fb9762003-03-23 01:06:05 +0000547 }
ths0da46a62007-10-20 20:23:07 +0000548 return ret;
bellard66fb9762003-03-23 01:06:05 +0000549}
bellard31e31b82003-02-18 22:55:36 +0000550
bellard43fff232003-07-09 19:31:39 +0000551#ifndef offsetof
552#define offsetof(type, field) ((size_t) &((type *)0)->field)
553#endif
554
ths5fafdf22007-09-16 21:08:06 +0000555static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
bellard43fff232003-07-09 19:31:39 +0000556 const target_siginfo_t *info)
557{
558 tswap_siginfo(tinfo, info);
559 return 0;
560}
561
thsc3b5bc82007-12-02 06:31:25 +0000562static inline int current_exec_domain_sig(int sig)
563{
564 return /* current->exec_domain && current->exec_domain->signal_invmap
565 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
566}
567
bellard459a4012007-11-11 19:45:10 +0000568#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000569
570/* from the Linux kernel */
571
572struct target_fpreg {
573 uint16_t significand[4];
574 uint16_t exponent;
575};
576
577struct target_fpxreg {
578 uint16_t significand[4];
579 uint16_t exponent;
580 uint16_t padding[3];
581};
582
583struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000584 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000585};
586
587struct target_fpstate {
588 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000589 abi_ulong cw;
590 abi_ulong sw;
591 abi_ulong tag;
592 abi_ulong ipoff;
593 abi_ulong cssel;
594 abi_ulong dataoff;
595 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000596 struct target_fpreg _st[8];
597 uint16_t status;
598 uint16_t magic; /* 0xffff = regular FPU data only */
599
600 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000601 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
602 abi_ulong mxcsr;
603 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000604 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
605 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000606 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000607};
608
609#define X86_FXSR_MAGIC 0x0000
610
611struct target_sigcontext {
612 uint16_t gs, __gsh;
613 uint16_t fs, __fsh;
614 uint16_t es, __esh;
615 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000616 abi_ulong edi;
617 abi_ulong esi;
618 abi_ulong ebp;
619 abi_ulong esp;
620 abi_ulong ebx;
621 abi_ulong edx;
622 abi_ulong ecx;
623 abi_ulong eax;
624 abi_ulong trapno;
625 abi_ulong err;
626 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000627 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000628 abi_ulong eflags;
629 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000630 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000631 abi_ulong fpstate; /* pointer */
632 abi_ulong oldmask;
633 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000634};
635
bellard66fb9762003-03-23 01:06:05 +0000636struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000637 abi_ulong tuc_flags;
638 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +0000639 target_stack_t tuc_stack;
640 struct target_sigcontext tuc_mcontext;
641 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000642};
643
644struct sigframe
645{
blueswir1992f48a2007-10-14 16:27:31 +0000646 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000647 int sig;
648 struct target_sigcontext sc;
649 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000650 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000651 char retcode[8];
652};
653
654struct rt_sigframe
655{
blueswir1992f48a2007-10-14 16:27:31 +0000656 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000657 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000658 abi_ulong pinfo;
659 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000660 struct target_siginfo info;
661 struct target_ucontext uc;
662 struct target_fpstate fpstate;
663 char retcode[8];
664};
665
666/*
667 * Set up a signal frame.
668 */
669
bellard66fb9762003-03-23 01:06:05 +0000670/* XXX: save x87 state */
671static int
672setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000673 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000674{
675 int err = 0;
bellard775b58d2007-11-11 16:22:17 +0000676 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000677
bellard579a97f2007-11-11 14:26:47 +0000678 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000679 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
680 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
681 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
682 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000683 err |= __put_user(env->regs[R_EDI], &sc->edi);
684 err |= __put_user(env->regs[R_ESI], &sc->esi);
685 err |= __put_user(env->regs[R_EBP], &sc->ebp);
686 err |= __put_user(env->regs[R_ESP], &sc->esp);
687 err |= __put_user(env->regs[R_EBX], &sc->ebx);
688 err |= __put_user(env->regs[R_EDX], &sc->edx);
689 err |= __put_user(env->regs[R_ECX], &sc->ecx);
690 err |= __put_user(env->regs[R_EAX], &sc->eax);
bellard66099dd2003-05-08 15:34:02 +0000691 err |= __put_user(env->exception_index, &sc->trapno);
692 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000693 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000694 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000695 err |= __put_user(env->eflags, &sc->eflags);
696 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000697 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000698
bellard28be6232007-11-11 22:23:38 +0000699 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000700 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000701 magic = 0xffff;
702 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000703 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000704
bellard66fb9762003-03-23 01:06:05 +0000705 /* non-iBCS2 extensions.. */
706 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000707 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000708 return err;
709}
710
711/*
712 * Determine which stack to use..
713 */
714
bellard579a97f2007-11-11 14:26:47 +0000715static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000716get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000717{
718 unsigned long esp;
719
720 /* Default to using normal stack */
721 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000722 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000723 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000724 if (sas_ss_flags(esp) == 0)
725 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
726 }
bellard66fb9762003-03-23 01:06:05 +0000727
728 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000729 else
bellarda52c7572003-06-21 13:14:12 +0000730 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000731 !(ka->sa_flags & TARGET_SA_RESTORER) &&
732 ka->sa_restorer) {
733 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000734 }
bellard579a97f2007-11-11 14:26:47 +0000735 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000736}
737
bellard579a97f2007-11-11 14:26:47 +0000738/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000739static void setup_frame(int sig, struct target_sigaction *ka,
bellard66fb9762003-03-23 01:06:05 +0000740 target_sigset_t *set, CPUX86State *env)
741{
bellard579a97f2007-11-11 14:26:47 +0000742 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000743 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000744 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000745
bellard579a97f2007-11-11 14:26:47 +0000746 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000747
bellard579a97f2007-11-11 14:26:47 +0000748 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000749 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000750
thsc3b5bc82007-12-02 06:31:25 +0000751 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000752 &frame->sig);
753 if (err)
754 goto give_sigsegv;
755
bellard28be6232007-11-11 22:23:38 +0000756 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
757 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000758 if (err)
759 goto give_sigsegv;
760
bellard92319442004-06-19 16:58:13 +0000761 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
762 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
763 goto give_sigsegv;
764 }
bellard66fb9762003-03-23 01:06:05 +0000765
766 /* Set up to return from userspace. If provided, use a stub
767 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000768 if (ka->sa_flags & TARGET_SA_RESTORER) {
769 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000770 } else {
bellard775b58d2007-11-11 16:22:17 +0000771 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000772 abi_ulong retcode_addr;
773 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
774 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000775 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000776 val16 = 0xb858;
777 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000778 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000779 val16 = 0x80cd;
780 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000781 }
782
783 if (err)
784 goto give_sigsegv;
785
786 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000787 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000788 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000789
790 cpu_x86_load_seg(env, R_DS, __USER_DS);
791 cpu_x86_load_seg(env, R_ES, __USER_DS);
792 cpu_x86_load_seg(env, R_SS, __USER_DS);
793 cpu_x86_load_seg(env, R_CS, __USER_CS);
794 env->eflags &= ~TF_MASK;
795
bellard579a97f2007-11-11 14:26:47 +0000796 unlock_user_struct(frame, frame_addr, 1);
797
bellard66fb9762003-03-23 01:06:05 +0000798 return;
799
800give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000801 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000802 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000803 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000804 force_sig(TARGET_SIGSEGV /* , current */);
805}
806
bellard579a97f2007-11-11 14:26:47 +0000807/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000808static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard9de5e442003-03-23 16:49:39 +0000809 target_siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +0000810 target_sigset_t *set, CPUX86State *env)
811{
bellard28be6232007-11-11 22:23:38 +0000812 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000813 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000814 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000815
bellard579a97f2007-11-11 14:26:47 +0000816 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000817
bellard579a97f2007-11-11 14:26:47 +0000818 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000819 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000820
thsc3b5bc82007-12-02 06:31:25 +0000821 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000822 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000823 addr = frame_addr + offsetof(struct rt_sigframe, info);
824 err |= __put_user(addr, &frame->pinfo);
825 addr = frame_addr + offsetof(struct rt_sigframe, uc);
826 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000827 err |= copy_siginfo_to_user(&frame->info, info);
828 if (err)
829 goto give_sigsegv;
830
831 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000832 err |= __put_user(0, &frame->uc.tuc_flags);
833 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000834 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000835 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000836 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000837 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000838 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000839 &frame->uc.tuc_stack.ss_size);
840 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000841 env, set->sig[0],
842 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000843 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000844 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000845 goto give_sigsegv;
846 }
bellard66fb9762003-03-23 01:06:05 +0000847
848 /* Set up to return from userspace. If provided, use a stub
849 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000850 if (ka->sa_flags & TARGET_SA_RESTORER) {
851 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000852 } else {
bellard775b58d2007-11-11 16:22:17 +0000853 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000854 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
855 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000856 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000857 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000858 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000859 val16 = 0x80cd;
860 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000861 }
862
863 if (err)
864 goto give_sigsegv;
865
866 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000867 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000868 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000869
870 cpu_x86_load_seg(env, R_DS, __USER_DS);
871 cpu_x86_load_seg(env, R_ES, __USER_DS);
872 cpu_x86_load_seg(env, R_SS, __USER_DS);
873 cpu_x86_load_seg(env, R_CS, __USER_CS);
874 env->eflags &= ~TF_MASK;
875
bellard579a97f2007-11-11 14:26:47 +0000876 unlock_user_struct(frame, frame_addr, 1);
877
bellard66fb9762003-03-23 01:06:05 +0000878 return;
879
880give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000881 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000882 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000883 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000884 force_sig(TARGET_SIGSEGV /* , current */);
885}
886
887static int
888restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
889{
890 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000891 abi_ulong fpstate_addr;
892 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000893
bellard28be6232007-11-11 22:23:38 +0000894 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
895 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
896 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
897 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +0000898
bellard28be6232007-11-11 22:23:38 +0000899 env->regs[R_EDI] = tswapl(sc->edi);
900 env->regs[R_ESI] = tswapl(sc->esi);
901 env->regs[R_EBP] = tswapl(sc->ebp);
902 env->regs[R_ESP] = tswapl(sc->esp);
903 env->regs[R_EBX] = tswapl(sc->ebx);
904 env->regs[R_EDX] = tswapl(sc->edx);
905 env->regs[R_ECX] = tswapl(sc->ecx);
906 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +0000907
908 cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
909 cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +0000910
bellard28be6232007-11-11 22:23:38 +0000911 tmpflags = tswapl(sc->eflags);
912 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
913 // regs->orig_eax = -1; /* disable syscall checks */
914
915 fpstate_addr = tswapl(sc->fpstate);
916 if (fpstate_addr != 0) {
917 if (!access_ok(VERIFY_READ, fpstate_addr,
918 sizeof(struct target_fpstate)))
919 goto badframe;
920 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000921 }
922
bellard28be6232007-11-11 22:23:38 +0000923 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +0000924 return err;
bellard66fb9762003-03-23 01:06:05 +0000925badframe:
926 return 1;
bellard66fb9762003-03-23 01:06:05 +0000927}
928
929long do_sigreturn(CPUX86State *env)
930{
bellard579a97f2007-11-11 14:26:47 +0000931 struct sigframe *frame;
932 abi_ulong frame_addr = env->regs[R_ESP] - 8;
bellard66fb9762003-03-23 01:06:05 +0000933 target_sigset_t target_set;
934 sigset_t set;
935 int eax, i;
936
bellard447db212003-05-10 15:10:36 +0000937#if defined(DEBUG_SIGNAL)
938 fprintf(stderr, "do_sigreturn\n");
939#endif
bellard579a97f2007-11-11 14:26:47 +0000940 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
941 goto badframe;
bellard66fb9762003-03-23 01:06:05 +0000942 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +0000943 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
944 goto badframe;
945 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
946 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
947 goto badframe;
948 }
bellard66fb9762003-03-23 01:06:05 +0000949
bellard92319442004-06-19 16:58:13 +0000950 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +0000951 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +0000952
bellard66fb9762003-03-23 01:06:05 +0000953 /* restore registers */
954 if (restore_sigcontext(env, &frame->sc, &eax))
955 goto badframe;
bellard579a97f2007-11-11 14:26:47 +0000956 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +0000957 return eax;
958
959badframe:
bellard579a97f2007-11-11 14:26:47 +0000960 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +0000961 force_sig(TARGET_SIGSEGV);
962 return 0;
963}
964
965long do_rt_sigreturn(CPUX86State *env)
966{
bellard28be6232007-11-11 22:23:38 +0000967 abi_ulong frame_addr;
968 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +0000969 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +0000970 int eax;
971
bellard28be6232007-11-11 22:23:38 +0000972 frame_addr = env->regs[R_ESP] - 4;
973 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
974 goto badframe;
bellardb8076a72005-04-07 22:20:31 +0000975 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +0000976 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +0000977
bellardb8076a72005-04-07 22:20:31 +0000978 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +0000979 goto badframe;
980
bellard28be6232007-11-11 22:23:38 +0000981 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
982 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +0000983 goto badframe;
thsa04e1342007-09-27 13:57:58 +0000984
bellard28be6232007-11-11 22:23:38 +0000985 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +0000986 return eax;
987
988badframe:
bellard28be6232007-11-11 22:23:38 +0000989 unlock_user_struct(frame, frame_addr, 0);
990 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +0000991 return 0;
992}
993
bellard43fff232003-07-09 19:31:39 +0000994#elif defined(TARGET_ARM)
995
996struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +0000997 abi_ulong trap_no;
998 abi_ulong error_code;
999 abi_ulong oldmask;
1000 abi_ulong arm_r0;
1001 abi_ulong arm_r1;
1002 abi_ulong arm_r2;
1003 abi_ulong arm_r3;
1004 abi_ulong arm_r4;
1005 abi_ulong arm_r5;
1006 abi_ulong arm_r6;
1007 abi_ulong arm_r7;
1008 abi_ulong arm_r8;
1009 abi_ulong arm_r9;
1010 abi_ulong arm_r10;
1011 abi_ulong arm_fp;
1012 abi_ulong arm_ip;
1013 abi_ulong arm_sp;
1014 abi_ulong arm_lr;
1015 abi_ulong arm_pc;
1016 abi_ulong arm_cpsr;
1017 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001018};
1019
pbrooka745ec62008-05-06 15:36:17 +00001020struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001021 abi_ulong tuc_flags;
1022 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +00001023 target_stack_t tuc_stack;
1024 struct target_sigcontext tuc_mcontext;
1025 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001026};
1027
pbrooka745ec62008-05-06 15:36:17 +00001028struct target_ucontext_v2 {
1029 abi_ulong tuc_flags;
1030 abi_ulong tuc_link;
1031 target_stack_t tuc_stack;
1032 struct target_sigcontext tuc_mcontext;
1033 target_sigset_t tuc_sigmask; /* mask last for extensibility */
1034 char __unused[128 - sizeof(sigset_t)];
1035 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1036};
1037
pbrooka8c33202008-05-07 23:22:46 +00001038struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001039{
1040 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001041 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1042 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001043};
1044
pbrooka8c33202008-05-07 23:22:46 +00001045struct sigframe_v2
1046{
1047 struct target_ucontext_v2 uc;
1048 abi_ulong retcode;
1049};
1050
pbrooka745ec62008-05-06 15:36:17 +00001051struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001052{
bellardf8b0aa22007-11-11 23:03:42 +00001053 abi_ulong pinfo;
1054 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001055 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001056 struct target_ucontext_v1 uc;
1057 abi_ulong retcode;
1058};
1059
1060struct rt_sigframe_v2
1061{
1062 struct target_siginfo info;
1063 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001064 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001065};
1066
1067#define TARGET_CONFIG_CPU_32 1
1068
1069/*
1070 * For ARM syscalls, we encode the syscall number into the instruction.
1071 */
1072#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1073#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1074
1075/*
1076 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1077 * need two 16-bit instructions.
1078 */
1079#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1080#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1081
blueswir1992f48a2007-10-14 16:27:31 +00001082static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001083 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1084 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1085};
1086
1087
bellard43fff232003-07-09 19:31:39 +00001088#define __get_user_error(x,p,e) __get_user(x, p)
1089
1090static inline int valid_user_regs(CPUState *regs)
1091{
1092 return 1;
1093}
1094
pbrooka8c33202008-05-07 23:22:46 +00001095static void
bellard43fff232003-07-09 19:31:39 +00001096setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
bellardf8b0aa22007-11-11 23:03:42 +00001097 CPUState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001098{
pbrooka8c33202008-05-07 23:22:46 +00001099 __put_user(env->regs[0], &sc->arm_r0);
1100 __put_user(env->regs[1], &sc->arm_r1);
1101 __put_user(env->regs[2], &sc->arm_r2);
1102 __put_user(env->regs[3], &sc->arm_r3);
1103 __put_user(env->regs[4], &sc->arm_r4);
1104 __put_user(env->regs[5], &sc->arm_r5);
1105 __put_user(env->regs[6], &sc->arm_r6);
1106 __put_user(env->regs[7], &sc->arm_r7);
1107 __put_user(env->regs[8], &sc->arm_r8);
1108 __put_user(env->regs[9], &sc->arm_r9);
1109 __put_user(env->regs[10], &sc->arm_r10);
1110 __put_user(env->regs[11], &sc->arm_fp);
1111 __put_user(env->regs[12], &sc->arm_ip);
1112 __put_user(env->regs[13], &sc->arm_sp);
1113 __put_user(env->regs[14], &sc->arm_lr);
1114 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001115#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001116 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001117#endif
1118
pbrooka8c33202008-05-07 23:22:46 +00001119 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1120 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1121 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1122 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001123}
1124
bellard579a97f2007-11-11 14:26:47 +00001125static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00001126get_sigframe(struct target_sigaction *ka, CPUState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001127{
1128 unsigned long sp = regs->regs[13];
1129
bellard43fff232003-07-09 19:31:39 +00001130 /*
1131 * This is the X/Open sanctioned signal stack switching.
1132 */
pbrook624f7972008-05-31 16:11:38 +00001133 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001134 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001135 /*
1136 * ATPCS B01 mandates 8-byte alignment
1137 */
bellard579a97f2007-11-11 14:26:47 +00001138 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001139}
1140
1141static int
pbrook624f7972008-05-31 16:11:38 +00001142setup_return(CPUState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001143 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001144{
pbrook624f7972008-05-31 16:11:38 +00001145 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001146 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001147 int thumb = handler & 1;
bellard43fff232003-07-09 19:31:39 +00001148
pbrook624f7972008-05-31 16:11:38 +00001149 if (ka->sa_flags & TARGET_SA_RESTORER) {
1150 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001151 } else {
1152 unsigned int idx = thumb;
1153
pbrook624f7972008-05-31 16:11:38 +00001154 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001155 idx += 2;
1156
1157 if (__put_user(retcodes[idx], rc))
1158 return 1;
1159#if 0
blueswir1992f48a2007-10-14 16:27:31 +00001160 flush_icache_range((abi_ulong)rc,
1161 (abi_ulong)(rc + 1));
bellard43fff232003-07-09 19:31:39 +00001162#endif
bellardf8b0aa22007-11-11 23:03:42 +00001163 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001164 }
1165
1166 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001167 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001168 env->regs[14] = retcode;
1169 env->regs[15] = handler & (thumb ? ~1 : ~3);
pbrook75b680e2008-03-21 16:07:30 +00001170 env->thumb = thumb;
bellard43fff232003-07-09 19:31:39 +00001171
bellardb5ff1b32005-11-26 10:38:39 +00001172#if 0
bellard43fff232003-07-09 19:31:39 +00001173#ifdef TARGET_CONFIG_CPU_32
1174 env->cpsr = cpsr;
1175#endif
bellardb5ff1b32005-11-26 10:38:39 +00001176#endif
bellard43fff232003-07-09 19:31:39 +00001177
1178 return 0;
1179}
1180
pbrooka8c33202008-05-07 23:22:46 +00001181static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
1182 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001183{
pbrooka8c33202008-05-07 23:22:46 +00001184 struct target_sigaltstack stack;
1185 int i;
1186
1187 /* Clear all the bits of the ucontext we don't use. */
1188 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1189
1190 memset(&stack, 0, sizeof(stack));
1191 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1192 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1193 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1194 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1195
1196 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
1197 /* FIXME: Save coprocessor signal frame. */
1198 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1199 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1200 }
1201}
1202
1203/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001204static void setup_frame_v1(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001205 target_sigset_t *set, CPUState *regs)
1206{
1207 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001208 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001209 int i;
bellard43fff232003-07-09 19:31:39 +00001210
bellard579a97f2007-11-11 14:26:47 +00001211 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1212 return;
1213
pbrooka8c33202008-05-07 23:22:46 +00001214 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001215
bellard92319442004-06-19 16:58:13 +00001216 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1217 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001218 goto end;
bellard43fff232003-07-09 19:31:39 +00001219 }
1220
pbrooka8c33202008-05-07 23:22:46 +00001221 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1222 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001223
1224end:
1225 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001226}
1227
pbrook624f7972008-05-31 16:11:38 +00001228static void setup_frame_v2(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001229 target_sigset_t *set, CPUState *regs)
1230{
1231 struct sigframe_v2 *frame;
1232 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1233
1234 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1235 return;
1236
1237 setup_sigframe_v2(&frame->uc, set, regs);
1238
1239 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1240 frame_addr + offsetof(struct sigframe_v2, retcode));
1241
1242 unlock_user_struct(frame, frame_addr, 1);
1243}
1244
pbrook624f7972008-05-31 16:11:38 +00001245static void setup_frame(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001246 target_sigset_t *set, CPUState *regs)
1247{
1248 if (get_osversion() >= 0x020612) {
1249 setup_frame_v2(usig, ka, set, regs);
1250 } else {
1251 setup_frame_v1(usig, ka, set, regs);
1252 }
bellard43fff232003-07-09 19:31:39 +00001253}
1254
bellard579a97f2007-11-11 14:26:47 +00001255/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001256static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001257 target_siginfo_t *info,
1258 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001259{
pbrooka745ec62008-05-06 15:36:17 +00001260 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001261 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001262 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001263 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001264 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001265
bellard579a97f2007-11-11 14:26:47 +00001266 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001267 return /* 1 */;
1268
pbrooka745ec62008-05-06 15:36:17 +00001269 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001270 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001271 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001272 __put_user(uc_addr, &frame->puc);
1273 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001274
1275 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001276 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001277
thsa04e1342007-09-27 13:57:58 +00001278 memset(&stack, 0, sizeof(stack));
1279 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1280 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1281 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001282 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001283
pbrooka8c33202008-05-07 23:22:46 +00001284 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001285 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001286 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001287 goto end;
bellard92319442004-06-19 16:58:13 +00001288 }
bellard43fff232003-07-09 19:31:39 +00001289
pbrooka8c33202008-05-07 23:22:46 +00001290 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1291 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001292
pbrooka8c33202008-05-07 23:22:46 +00001293 env->regs[1] = info_addr;
1294 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001295
1296end:
1297 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001298}
1299
pbrook624f7972008-05-31 16:11:38 +00001300static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001301 target_siginfo_t *info,
1302 target_sigset_t *set, CPUState *env)
1303{
1304 struct rt_sigframe_v2 *frame;
1305 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001306 abi_ulong info_addr, uc_addr;
1307
1308 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1309 return /* 1 */;
1310
1311 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1312 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001313 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001314
pbrooka8c33202008-05-07 23:22:46 +00001315 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001316
pbrooka8c33202008-05-07 23:22:46 +00001317 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1318 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001319
pbrooka8c33202008-05-07 23:22:46 +00001320 env->regs[1] = info_addr;
1321 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001322
bellard579a97f2007-11-11 14:26:47 +00001323 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001324}
1325
pbrook624f7972008-05-31 16:11:38 +00001326static void setup_rt_frame(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001327 target_siginfo_t *info,
1328 target_sigset_t *set, CPUState *env)
1329{
1330 if (get_osversion() >= 0x020612) {
1331 setup_rt_frame_v2(usig, ka, info, set, env);
1332 } else {
1333 setup_rt_frame_v1(usig, ka, info, set, env);
1334 }
1335}
1336
bellard43fff232003-07-09 19:31:39 +00001337static int
1338restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
1339{
1340 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001341 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001342
1343 __get_user_error(env->regs[0], &sc->arm_r0, err);
1344 __get_user_error(env->regs[1], &sc->arm_r1, err);
1345 __get_user_error(env->regs[2], &sc->arm_r2, err);
1346 __get_user_error(env->regs[3], &sc->arm_r3, err);
1347 __get_user_error(env->regs[4], &sc->arm_r4, err);
1348 __get_user_error(env->regs[5], &sc->arm_r5, err);
1349 __get_user_error(env->regs[6], &sc->arm_r6, err);
1350 __get_user_error(env->regs[7], &sc->arm_r7, err);
1351 __get_user_error(env->regs[8], &sc->arm_r8, err);
1352 __get_user_error(env->regs[9], &sc->arm_r9, err);
1353 __get_user_error(env->regs[10], &sc->arm_r10, err);
1354 __get_user_error(env->regs[11], &sc->arm_fp, err);
1355 __get_user_error(env->regs[12], &sc->arm_ip, err);
1356 __get_user_error(env->regs[13], &sc->arm_sp, err);
1357 __get_user_error(env->regs[14], &sc->arm_lr, err);
1358 __get_user_error(env->regs[15], &sc->arm_pc, err);
1359#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001360 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001361 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001362#endif
1363
1364 err |= !valid_user_regs(env);
1365
1366 return err;
1367}
1368
pbrooka8c33202008-05-07 23:22:46 +00001369long do_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001370{
bellardf8b0aa22007-11-11 23:03:42 +00001371 abi_ulong frame_addr;
pbrooka8c33202008-05-07 23:22:46 +00001372 struct sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001373 target_sigset_t set;
1374 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001375 int i;
bellard43fff232003-07-09 19:31:39 +00001376
1377 /*
1378 * Since we stacked the signal on a 64-bit boundary,
1379 * then 'sp' should be word aligned here. If it's
1380 * not, then the user is trying to mess with us.
1381 */
1382 if (env->regs[13] & 7)
1383 goto badframe;
1384
bellardf8b0aa22007-11-11 23:03:42 +00001385 frame_addr = env->regs[13];
1386 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1387 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001388
bellard92319442004-06-19 16:58:13 +00001389 if (__get_user(set.sig[0], &frame->sc.oldmask))
1390 goto badframe;
1391 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1392 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1393 goto badframe;
1394 }
bellard43fff232003-07-09 19:31:39 +00001395
bellard92319442004-06-19 16:58:13 +00001396 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001397 sigprocmask(SIG_SETMASK, &host_set, NULL);
1398
1399 if (restore_sigcontext(env, &frame->sc))
1400 goto badframe;
1401
1402#if 0
1403 /* Send SIGTRAP if we're single-stepping */
1404 if (ptrace_cancel_bpt(current))
1405 send_sig(SIGTRAP, current, 1);
1406#endif
bellardf8b0aa22007-11-11 23:03:42 +00001407 unlock_user_struct(frame, frame_addr, 0);
1408 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001409
1410badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001411 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001412 force_sig(SIGSEGV /* , current */);
1413 return 0;
1414}
1415
pbrooka8c33202008-05-07 23:22:46 +00001416static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr,
1417 struct target_ucontext_v2 *uc)
1418{
1419 sigset_t host_set;
1420
1421 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1422 sigprocmask(SIG_SETMASK, &host_set, NULL);
1423
1424 if (restore_sigcontext(env, &uc->tuc_mcontext))
1425 return 1;
1426
1427 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1428 return 1;
1429
1430#if 0
1431 /* Send SIGTRAP if we're single-stepping */
1432 if (ptrace_cancel_bpt(current))
1433 send_sig(SIGTRAP, current, 1);
1434#endif
1435
1436 return 0;
1437}
1438
1439long do_sigreturn_v2(CPUState *env)
1440{
1441 abi_ulong frame_addr;
1442 struct sigframe_v2 *frame;
1443
1444 /*
1445 * Since we stacked the signal on a 64-bit boundary,
1446 * then 'sp' should be word aligned here. If it's
1447 * not, then the user is trying to mess with us.
1448 */
1449 if (env->regs[13] & 7)
1450 goto badframe;
1451
1452 frame_addr = env->regs[13];
1453 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1454 goto badframe;
1455
1456 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1457 goto badframe;
1458
1459 unlock_user_struct(frame, frame_addr, 0);
1460 return env->regs[0];
1461
1462badframe:
1463 unlock_user_struct(frame, frame_addr, 0);
1464 force_sig(SIGSEGV /* , current */);
1465 return 0;
1466}
1467
1468long do_sigreturn(CPUState *env)
1469{
1470 if (get_osversion() >= 0x020612) {
1471 return do_sigreturn_v2(env);
1472 } else {
1473 return do_sigreturn_v1(env);
1474 }
1475}
1476
pbrooka745ec62008-05-06 15:36:17 +00001477long do_rt_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001478{
bellardf8b0aa22007-11-11 23:03:42 +00001479 abi_ulong frame_addr;
pbrooka745ec62008-05-06 15:36:17 +00001480 struct rt_sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001481 sigset_t host_set;
1482
1483 /*
1484 * Since we stacked the signal on a 64-bit boundary,
1485 * then 'sp' should be word aligned here. If it's
1486 * not, then the user is trying to mess with us.
1487 */
1488 if (env->regs[13] & 7)
1489 goto badframe;
1490
bellardf8b0aa22007-11-11 23:03:42 +00001491 frame_addr = env->regs[13];
1492 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1493 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001494
bellardb8076a72005-04-07 22:20:31 +00001495 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00001496 sigprocmask(SIG_SETMASK, &host_set, NULL);
1497
bellardb8076a72005-04-07 22:20:31 +00001498 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00001499 goto badframe;
1500
pbrooka745ec62008-05-06 15:36:17 +00001501 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
thsa04e1342007-09-27 13:57:58 +00001502 goto badframe;
1503
bellard43fff232003-07-09 19:31:39 +00001504#if 0
1505 /* Send SIGTRAP if we're single-stepping */
1506 if (ptrace_cancel_bpt(current))
1507 send_sig(SIGTRAP, current, 1);
1508#endif
bellardf8b0aa22007-11-11 23:03:42 +00001509 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001510 return env->regs[0];
1511
1512badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001513 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001514 force_sig(SIGSEGV /* , current */);
1515 return 0;
1516}
1517
pbrooka745ec62008-05-06 15:36:17 +00001518long do_rt_sigreturn_v2(CPUState *env)
1519{
1520 abi_ulong frame_addr;
1521 struct rt_sigframe_v2 *frame;
pbrooka745ec62008-05-06 15:36:17 +00001522
1523 /*
1524 * Since we stacked the signal on a 64-bit boundary,
1525 * then 'sp' should be word aligned here. If it's
1526 * not, then the user is trying to mess with us.
1527 */
1528 if (env->regs[13] & 7)
1529 goto badframe;
1530
1531 frame_addr = env->regs[13];
1532 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1533 goto badframe;
1534
pbrooka8c33202008-05-07 23:22:46 +00001535 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1536 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00001537
pbrooka745ec62008-05-06 15:36:17 +00001538 unlock_user_struct(frame, frame_addr, 0);
1539 return env->regs[0];
1540
1541badframe:
1542 unlock_user_struct(frame, frame_addr, 0);
1543 force_sig(SIGSEGV /* , current */);
1544 return 0;
1545}
1546
1547long do_rt_sigreturn(CPUState *env)
1548{
1549 if (get_osversion() >= 0x020612) {
1550 return do_rt_sigreturn_v2(env);
1551 } else {
1552 return do_rt_sigreturn_v1(env);
1553 }
1554}
1555
bellard6d5e2162004-09-30 22:04:13 +00001556#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00001557
bellard6d5e2162004-09-30 22:04:13 +00001558#define __SUNOS_MAXWIN 31
1559
1560/* This is what SunOS does, so shall I. */
1561struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001562 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00001563
blueswir1992f48a2007-10-14 16:27:31 +00001564 abi_ulong sigc_mask; /* sigmask to restore */
1565 abi_ulong sigc_sp; /* stack pointer */
1566 abi_ulong sigc_pc; /* program counter */
1567 abi_ulong sigc_npc; /* next program counter */
1568 abi_ulong sigc_psr; /* for condition codes etc */
1569 abi_ulong sigc_g1; /* User uses these two registers */
1570 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00001571
1572 /* Now comes information regarding the users window set
1573 * at the time of the signal.
1574 */
blueswir1992f48a2007-10-14 16:27:31 +00001575 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00001576
1577 /* stack ptrs for each regwin buf */
1578 char *sigc_spbuf[__SUNOS_MAXWIN];
1579
1580 /* Windows to restore after signal */
1581 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001582 abi_ulong locals[8];
1583 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00001584 } sigc_wbuf[__SUNOS_MAXWIN];
1585};
1586/* A Sparc stack frame */
1587struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00001588 abi_ulong locals[8];
1589 abi_ulong ins[6];
bellard6d5e2162004-09-30 22:04:13 +00001590 struct sparc_stackf *fp;
blueswir1992f48a2007-10-14 16:27:31 +00001591 abi_ulong callers_pc;
bellard6d5e2162004-09-30 22:04:13 +00001592 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00001593 abi_ulong xargs[6];
1594 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00001595};
1596
1597typedef struct {
1598 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001599 abi_ulong psr;
1600 abi_ulong pc;
1601 abi_ulong npc;
1602 abi_ulong y;
1603 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00001604 } si_regs;
1605 int si_mask;
1606} __siginfo_t;
1607
1608typedef struct {
1609 unsigned long si_float_regs [32];
1610 unsigned long si_fsr;
1611 unsigned long si_fpqdepth;
1612 struct {
1613 unsigned long *insn_addr;
1614 unsigned long insn;
1615 } si_fpqueue [16];
bellard74ccb342006-07-18 21:23:34 +00001616} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00001617
1618
1619struct target_signal_frame {
1620 struct sparc_stackf ss;
1621 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00001622 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00001623 abi_ulong insns[2] __attribute__ ((aligned (8)));
1624 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
1625 abi_ulong extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001626 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001627};
1628struct target_rt_signal_frame {
1629 struct sparc_stackf ss;
1630 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00001631 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00001632 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00001633 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00001634 unsigned int insns[2];
1635 stack_t stack;
1636 unsigned int extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001637 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001638};
1639
bellarde80cfcf2004-12-19 23:18:01 +00001640#define UREG_O0 16
1641#define UREG_O6 22
1642#define UREG_I0 0
1643#define UREG_I1 1
1644#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00001645#define UREG_I3 3
1646#define UREG_I4 4
1647#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00001648#define UREG_I6 6
1649#define UREG_I7 7
1650#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00001651#define UREG_FP UREG_I6
1652#define UREG_SP UREG_O6
1653
pbrook624f7972008-05-31 16:11:38 +00001654static inline abi_ulong get_sigframe(struct target_sigaction *sa,
bellard459a4012007-11-11 19:45:10 +00001655 CPUState *env, unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00001656{
bellard459a4012007-11-11 19:45:10 +00001657 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00001658
1659 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00001660
1661 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00001662 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00001663 if (!on_sig_stack(sp)
1664 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
1665 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00001666 }
bellard459a4012007-11-11 19:45:10 +00001667 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00001668}
1669
1670static int
blueswir1992f48a2007-10-14 16:27:31 +00001671setup___siginfo(__siginfo_t *si, CPUState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00001672{
1673 int err = 0, i;
1674
bellard6d5e2162004-09-30 22:04:13 +00001675 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00001676 err |= __put_user(env->pc, &si->si_regs.pc);
1677 err |= __put_user(env->npc, &si->si_regs.npc);
1678 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001679 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00001680 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
1681 }
bellarda315a142005-01-30 22:59:18 +00001682 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001683 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00001684 }
bellard6d5e2162004-09-30 22:04:13 +00001685 err |= __put_user(mask, &si->si_mask);
1686 return err;
1687}
bellarde80cfcf2004-12-19 23:18:01 +00001688
bellard80a9d032005-01-03 23:31:27 +00001689#if 0
bellard6d5e2162004-09-30 22:04:13 +00001690static int
1691setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
1692 CPUState *env, unsigned long mask)
1693{
1694 int err = 0;
1695
1696 err |= __put_user(mask, &sc->sigc_mask);
1697 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
1698 err |= __put_user(env->pc, &sc->sigc_pc);
1699 err |= __put_user(env->npc, &sc->sigc_npc);
1700 err |= __put_user(env->psr, &sc->sigc_psr);
1701 err |= __put_user(env->gregs[1], &sc->sigc_g1);
1702 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
1703
1704 return err;
1705}
bellard80a9d032005-01-03 23:31:27 +00001706#endif
bellard6d5e2162004-09-30 22:04:13 +00001707#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
1708
pbrook624f7972008-05-31 16:11:38 +00001709static void setup_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001710 target_sigset_t *set, CPUState *env)
1711{
bellard459a4012007-11-11 19:45:10 +00001712 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001713 struct target_signal_frame *sf;
1714 int sigframe_size, err, i;
1715
1716 /* 1. Make sure everything is clean */
1717 //synchronize_user_stack();
1718
1719 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00001720 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00001721
bellard459a4012007-11-11 19:45:10 +00001722 sf = lock_user(VERIFY_WRITE, sf_addr,
1723 sizeof(struct target_signal_frame), 0);
1724 if (!sf)
1725 goto sigsegv;
1726
bellarde80cfcf2004-12-19 23:18:01 +00001727 //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
bellard6d5e2162004-09-30 22:04:13 +00001728#if 0
1729 if (invalid_frame_pointer(sf, sigframe_size))
1730 goto sigill_and_return;
1731#endif
1732 /* 2. Save the current process state */
1733 err = setup___siginfo(&sf->info, env, set->sig[0]);
1734 err |= __put_user(0, &sf->extra_size);
1735
1736 //err |= save_fpu_state(regs, &sf->fpu_state);
1737 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
1738
1739 err |= __put_user(set->sig[0], &sf->info.si_mask);
1740 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
1741 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
1742 }
1743
bellarda315a142005-01-30 22:59:18 +00001744 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001745 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00001746 }
bellarda315a142005-01-30 22:59:18 +00001747 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001748 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00001749 }
bellard6d5e2162004-09-30 22:04:13 +00001750 if (err)
1751 goto sigsegv;
1752
1753 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00001754 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001755 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00001756 env->regwptr[UREG_I1] = sf_addr +
1757 offsetof(struct target_signal_frame, info);
1758 env->regwptr[UREG_I2] = sf_addr +
1759 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00001760
1761 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00001762 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00001763 env->npc = (env->pc + 4);
1764 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00001765 if (ka->sa_restorer)
1766 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00001767 else {
bellard775b58d2007-11-11 16:22:17 +00001768 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00001769
1770 env->regwptr[UREG_I7] = sf_addr +
1771 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00001772
1773 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00001774 val32 = 0x821020d8;
1775 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00001776
1777 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00001778 val32 = 0x91d02010;
1779 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00001780 if (err)
1781 goto sigsegv;
1782
1783 /* Flush instruction space. */
1784 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00001785 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00001786 }
bellard459a4012007-11-11 19:45:10 +00001787 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001788 return;
bellard459a4012007-11-11 19:45:10 +00001789#if 0
1790sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00001791 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00001792#endif
bellard6d5e2162004-09-30 22:04:13 +00001793sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00001794 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00001795 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001796 force_sig(TARGET_SIGSEGV);
1797}
1798static inline int
bellard74ccb342006-07-18 21:23:34 +00001799restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00001800{
1801 int err;
1802#if 0
1803#ifdef CONFIG_SMP
1804 if (current->flags & PF_USEDFPU)
1805 regs->psr &= ~PSR_EF;
1806#else
1807 if (current == last_task_used_math) {
1808 last_task_used_math = 0;
1809 regs->psr &= ~PSR_EF;
1810 }
1811#endif
1812 current->used_math = 1;
1813 current->flags &= ~PF_USEDFPU;
1814#endif
1815#if 0
1816 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
1817 return -EFAULT;
1818#endif
1819
bellardfafffae2006-10-28 12:09:16 +00001820#if 0
1821 /* XXX: incorrect */
bellard6d5e2162004-09-30 22:04:13 +00001822 err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
1823 (sizeof(unsigned long) * 32));
bellardfafffae2006-10-28 12:09:16 +00001824#endif
bellard6d5e2162004-09-30 22:04:13 +00001825 err |= __get_user(env->fsr, &fpu->si_fsr);
1826#if 0
1827 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
1828 if (current->thread.fpqdepth != 0)
1829 err |= __copy_from_user(&current->thread.fpqueue[0],
1830 &fpu->si_fpqueue[0],
1831 ((sizeof(unsigned long) +
1832 (sizeof(unsigned long *)))*16));
1833#endif
1834 return err;
1835}
1836
1837
pbrook624f7972008-05-31 16:11:38 +00001838static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001839 target_siginfo_t *info,
1840 target_sigset_t *set, CPUState *env)
1841{
1842 fprintf(stderr, "setup_rt_frame: not implemented\n");
1843}
1844
1845long do_sigreturn(CPUState *env)
1846{
bellardf8b0aa22007-11-11 23:03:42 +00001847 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001848 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00001849 uint32_t up_psr, pc, npc;
bellard6d5e2162004-09-30 22:04:13 +00001850 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00001851 sigset_t host_set;
bellardf8b0aa22007-11-11 23:03:42 +00001852 abi_ulong fpu_save_addr;
bellarde80cfcf2004-12-19 23:18:01 +00001853 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00001854
bellardf8b0aa22007-11-11 23:03:42 +00001855 sf_addr = env->regwptr[UREG_FP];
1856 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
1857 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00001858#if 0
bellarde80cfcf2004-12-19 23:18:01 +00001859 fprintf(stderr, "sigreturn\n");
1860 fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
bellard80a9d032005-01-03 23:31:27 +00001861#endif
bellarde80cfcf2004-12-19 23:18:01 +00001862 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00001863
1864 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00001865
bellardf8b0aa22007-11-11 23:03:42 +00001866 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00001867 goto segv_and_exit;
1868
1869 err = __get_user(pc, &sf->info.si_regs.pc);
1870 err |= __get_user(npc, &sf->info.si_regs.npc);
1871
bellard6d5e2162004-09-30 22:04:13 +00001872 if ((pc | npc) & 3)
1873 goto segv_and_exit;
1874
1875 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00001876 err |= __get_user(up_psr, &sf->info.si_regs.psr);
1877
bellard6d5e2162004-09-30 22:04:13 +00001878 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00001879 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
1880 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
1881
1882 env->pc = pc;
1883 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00001884 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001885 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001886 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
1887 }
bellarda315a142005-01-30 22:59:18 +00001888 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001889 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
1890 }
bellard6d5e2162004-09-30 22:04:13 +00001891
bellardf8b0aa22007-11-11 23:03:42 +00001892 err |= __get_user(fpu_save_addr, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001893
bellarde80cfcf2004-12-19 23:18:01 +00001894 //if (fpu_save)
1895 // err |= restore_fpu_state(env, fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001896
1897 /* This is pretty much atomic, no amount locking would prevent
1898 * the races which exist anyways.
1899 */
1900 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00001901 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1902 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
1903 }
1904
1905 target_to_host_sigset_internal(&host_set, &set);
1906 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00001907
1908 if (err)
1909 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00001910 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001911 return env->regwptr[0];
1912
1913segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00001914 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001915 force_sig(TARGET_SIGSEGV);
1916}
1917
1918long do_rt_sigreturn(CPUState *env)
1919{
1920 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00001921 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00001922}
1923
bellard459a4012007-11-11 19:45:10 +00001924#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00001925#define MC_TSTATE 0
1926#define MC_PC 1
1927#define MC_NPC 2
1928#define MC_Y 3
1929#define MC_G1 4
1930#define MC_G2 5
1931#define MC_G3 6
1932#define MC_G4 7
1933#define MC_G5 8
1934#define MC_G6 9
1935#define MC_G7 10
1936#define MC_O0 11
1937#define MC_O1 12
1938#define MC_O2 13
1939#define MC_O3 14
1940#define MC_O4 15
1941#define MC_O5 16
1942#define MC_O6 17
1943#define MC_O7 18
1944#define MC_NGREG 19
1945
blueswir1992f48a2007-10-14 16:27:31 +00001946typedef abi_ulong target_mc_greg_t;
blueswir15bfb56b2007-10-05 17:01:51 +00001947typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
1948
1949struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00001950 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00001951 uint32_t mcfq_insn;
1952};
1953
1954struct target_mc_fpu {
1955 union {
1956 uint32_t sregs[32];
1957 uint64_t dregs[32];
1958 //uint128_t qregs[16];
1959 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00001960 abi_ulong mcfpu_fsr;
1961 abi_ulong mcfpu_fprs;
1962 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00001963 struct target_mc_fq *mcfpu_fq;
1964 unsigned char mcfpu_qcnt;
1965 unsigned char mcfpu_qentsz;
1966 unsigned char mcfpu_enab;
1967};
1968typedef struct target_mc_fpu target_mc_fpu_t;
1969
1970typedef struct {
1971 target_mc_gregset_t mc_gregs;
1972 target_mc_greg_t mc_fp;
1973 target_mc_greg_t mc_i7;
1974 target_mc_fpu_t mc_fpregs;
1975} target_mcontext_t;
1976
1977struct target_ucontext {
1978 struct target_ucontext *uc_link;
blueswir1992f48a2007-10-14 16:27:31 +00001979 abi_ulong uc_flags;
blueswir15bfb56b2007-10-05 17:01:51 +00001980 target_sigset_t uc_sigmask;
1981 target_mcontext_t uc_mcontext;
1982};
1983
1984/* A V9 register window */
1985struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00001986 abi_ulong locals[8];
1987 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00001988};
1989
1990#define TARGET_STACK_BIAS 2047
1991
1992/* {set, get}context() needed for 64-bit SparcLinux userland. */
1993void sparc64_set_context(CPUSPARCState *env)
1994{
bellard459a4012007-11-11 19:45:10 +00001995 abi_ulong ucp_addr;
1996 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00001997 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00001998 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00001999 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002000 unsigned char fenab;
2001 int err;
2002 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002003
bellard459a4012007-11-11 19:45:10 +00002004 ucp_addr = env->regwptr[UREG_I0];
2005 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2006 goto do_sigsegv;
blueswir15bfb56b2007-10-05 17:01:51 +00002007 grp = &ucp->uc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002008 err = __get_user(pc, &((*grp)[MC_PC]));
2009 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002010 if (err || ((pc | npc) & 3))
2011 goto do_sigsegv;
2012 if (env->regwptr[UREG_I1]) {
2013 target_sigset_t target_set;
2014 sigset_t set;
2015
2016 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002017 if (__get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002018 goto do_sigsegv;
2019 } else {
bellard459a4012007-11-11 19:45:10 +00002020 abi_ulong *src, *dst;
2021 src = ucp->uc_sigmask.sig;
2022 dst = target_set.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002023 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002024 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002025 err |= __get_user(*dst, src);
blueswir15bfb56b2007-10-05 17:01:51 +00002026 if (err)
2027 goto do_sigsegv;
2028 }
2029 target_to_host_sigset_internal(&set, &target_set);
2030 sigprocmask(SIG_SETMASK, &set, NULL);
2031 }
2032 env->pc = pc;
2033 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002034 err |= __get_user(env->y, &((*grp)[MC_Y]));
2035 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002036 env->asi = (tstate >> 24) & 0xff;
2037 PUT_CCR(env, tstate >> 32);
2038 PUT_CWP64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002039 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2040 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2041 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2042 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2043 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2044 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2045 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2046 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2047 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2048 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2049 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2050 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2051 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2052 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2053 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002054
bellard579a97f2007-11-11 14:26:47 +00002055 err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp));
2056 err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002057
bellard459a4012007-11-11 19:45:10 +00002058 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2059 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2060 abi_ulong) != 0)
2061 goto do_sigsegv;
2062 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2063 abi_ulong) != 0)
2064 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002065 err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
2066 err |= __get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002067 {
2068 uint32_t *src, *dst;
2069 src = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2070 dst = env->fpr;
2071 /* XXX: check that the CPU storage is the same as user context */
2072 for (i = 0; i < 64; i++, dst++, src++)
2073 err |= __get_user(*dst, src);
2074 }
bellard579a97f2007-11-11 14:26:47 +00002075 err |= __get_user(env->fsr,
2076 &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
2077 err |= __get_user(env->gsr,
2078 &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002079 if (err)
2080 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002081 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002082 return;
2083 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002084 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002085 force_sig(SIGSEGV);
2086}
2087
2088void sparc64_get_context(CPUSPARCState *env)
2089{
bellard459a4012007-11-11 19:45:10 +00002090 abi_ulong ucp_addr;
2091 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00002092 target_mc_gregset_t *grp;
2093 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002094 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002095 int err;
2096 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002097 target_sigset_t target_set;
2098 sigset_t set;
2099
bellard459a4012007-11-11 19:45:10 +00002100 ucp_addr = env->regwptr[UREG_I0];
2101 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2102 goto do_sigsegv;
2103
blueswir15bfb56b2007-10-05 17:01:51 +00002104 mcp = &ucp->uc_mcontext;
2105 grp = &mcp->mc_gregs;
2106
2107 /* Skip over the trap instruction, first. */
2108 env->pc = env->npc;
2109 env->npc += 4;
2110
2111 err = 0;
2112
2113 sigprocmask(0, NULL, &set);
2114 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002115 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002116 err |= __put_user(target_set.sig[0],
2117 (abi_ulong *)&ucp->uc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002118 } else {
2119 abi_ulong *src, *dst;
2120 src = target_set.sig;
2121 dst = ucp->uc_sigmask.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002122 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002123 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002124 err |= __put_user(*src, dst);
blueswir15bfb56b2007-10-05 17:01:51 +00002125 if (err)
2126 goto do_sigsegv;
2127 }
2128
bellard459a4012007-11-11 19:45:10 +00002129 /* XXX: tstate must be saved properly */
2130 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002131 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2132 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2133 err |= __put_user(env->y, &((*grp)[MC_Y]));
2134 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2135 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2136 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2137 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2138 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2139 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2140 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2141 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2142 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2143 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2144 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2145 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2146 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2147 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2148 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002149
bellard459a4012007-11-11 19:45:10 +00002150 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2151 fp = i7 = 0;
2152 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2153 abi_ulong) != 0)
2154 goto do_sigsegv;
2155 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2156 abi_ulong) != 0)
2157 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002158 err |= __put_user(fp, &(mcp->mc_fp));
2159 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002160
bellard459a4012007-11-11 19:45:10 +00002161 {
2162 uint32_t *src, *dst;
2163 src = env->fpr;
2164 dst = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2165 /* XXX: check that the CPU storage is the same as user context */
2166 for (i = 0; i < 64; i++, dst++, src++)
2167 err |= __put_user(*src, dst);
2168 }
bellard579a97f2007-11-11 14:26:47 +00002169 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2170 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2171 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002172
2173 if (err)
2174 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002175 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002176 return;
2177 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002178 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002179 force_sig(SIGSEGV);
2180}
2181#endif
thsd26bc212007-11-08 18:05:37 +00002182#elif defined(TARGET_ABI_MIPSN64)
ths540635b2007-09-30 01:58:33 +00002183
2184# warning signal handling not implemented
2185
pbrook624f7972008-05-31 16:11:38 +00002186static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002187 target_sigset_t *set, CPUState *env)
2188{
2189 fprintf(stderr, "setup_frame: not implemented\n");
2190}
2191
pbrook624f7972008-05-31 16:11:38 +00002192static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002193 target_siginfo_t *info,
2194 target_sigset_t *set, CPUState *env)
2195{
2196 fprintf(stderr, "setup_rt_frame: not implemented\n");
2197}
2198
2199long do_sigreturn(CPUState *env)
2200{
2201 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002202 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002203}
2204
2205long do_rt_sigreturn(CPUState *env)
2206{
2207 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002208 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002209}
2210
thsd26bc212007-11-08 18:05:37 +00002211#elif defined(TARGET_ABI_MIPSN32)
ths540635b2007-09-30 01:58:33 +00002212
2213# warning signal handling not implemented
2214
pbrook624f7972008-05-31 16:11:38 +00002215static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002216 target_sigset_t *set, CPUState *env)
2217{
2218 fprintf(stderr, "setup_frame: not implemented\n");
2219}
2220
pbrook624f7972008-05-31 16:11:38 +00002221static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002222 target_siginfo_t *info,
2223 target_sigset_t *set, CPUState *env)
2224{
2225 fprintf(stderr, "setup_rt_frame: not implemented\n");
2226}
2227
2228long do_sigreturn(CPUState *env)
2229{
2230 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002231 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002232}
2233
2234long do_rt_sigreturn(CPUState *env)
2235{
2236 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002237 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002238}
2239
thsd26bc212007-11-08 18:05:37 +00002240#elif defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002241
2242struct target_sigcontext {
2243 uint32_t sc_regmask; /* Unused */
2244 uint32_t sc_status;
2245 uint64_t sc_pc;
2246 uint64_t sc_regs[32];
2247 uint64_t sc_fpregs[32];
2248 uint32_t sc_ownedfp; /* Unused */
2249 uint32_t sc_fpc_csr;
2250 uint32_t sc_fpc_eir; /* Unused */
2251 uint32_t sc_used_math;
2252 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
2253 uint64_t sc_mdhi;
2254 uint64_t sc_mdlo;
2255 target_ulong sc_hi1; /* Was sc_cause */
2256 target_ulong sc_lo1; /* Was sc_badvaddr */
2257 target_ulong sc_hi2; /* Was sc_sigset[4] */
2258 target_ulong sc_lo2;
2259 target_ulong sc_hi3;
2260 target_ulong sc_lo3;
2261};
2262
2263struct sigframe {
2264 uint32_t sf_ass[4]; /* argument save space for o32 */
2265 uint32_t sf_code[2]; /* signal trampoline */
2266 struct target_sigcontext sf_sc;
2267 target_sigset_t sf_mask;
2268};
2269
2270/* Install trampoline to jump back from signal handler */
2271static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2272{
2273 int err;
2274
2275 /*
2276 * Set up the return code ...
2277 *
2278 * li v0, __NR__foo_sigreturn
2279 * syscall
2280 */
2281
2282 err = __put_user(0x24020000 + syscall, tramp + 0);
2283 err |= __put_user(0x0000000c , tramp + 1);
2284 /* flush_cache_sigtramp((unsigned long) tramp); */
2285 return err;
2286}
2287
2288static inline int
2289setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2290{
2291 int err = 0;
2292
thsb5dc7732008-06-27 10:02:35 +00002293 err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002294
thsb5dc7732008-06-27 10:02:35 +00002295#define save_gp_reg(i) do { \
2296 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002297 } while(0)
2298 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
2299 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
2300 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
2301 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
2302 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
2303 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
2304 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
2305 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
2306 save_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002307#undef save_gp_reg
bellard106ec872006-06-27 21:08:10 +00002308
thsb5dc7732008-06-27 10:02:35 +00002309 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2310 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002311
2312 /* Not used yet, but might be useful if we ever have DSP suppport */
2313#if 0
2314 if (cpu_has_dsp) {
2315 err |= __put_user(mfhi1(), &sc->sc_hi1);
2316 err |= __put_user(mflo1(), &sc->sc_lo1);
2317 err |= __put_user(mfhi2(), &sc->sc_hi2);
2318 err |= __put_user(mflo2(), &sc->sc_lo2);
2319 err |= __put_user(mfhi3(), &sc->sc_hi3);
2320 err |= __put_user(mflo3(), &sc->sc_lo3);
2321 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2322 }
2323 /* same with 64 bit */
ths388bb212007-05-13 13:58:00 +00002324#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002325 err |= __put_user(regs->hi, &sc->sc_hi[0]);
2326 err |= __put_user(regs->lo, &sc->sc_lo[0]);
2327 if (cpu_has_dsp) {
2328 err |= __put_user(mfhi1(), &sc->sc_hi[1]);
2329 err |= __put_user(mflo1(), &sc->sc_lo[1]);
2330 err |= __put_user(mfhi2(), &sc->sc_hi[2]);
2331 err |= __put_user(mflo2(), &sc->sc_lo[2]);
2332 err |= __put_user(mfhi3(), &sc->sc_hi[3]);
2333 err |= __put_user(mflo3(), &sc->sc_lo[3]);
2334 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2335 }
ths388bb212007-05-13 13:58:00 +00002336#endif
2337#endif
bellard106ec872006-06-27 21:08:10 +00002338
ths388bb212007-05-13 13:58:00 +00002339#if 0
bellard106ec872006-06-27 21:08:10 +00002340 err |= __put_user(!!used_math(), &sc->sc_used_math);
2341
2342 if (!used_math())
2343 goto out;
2344
2345 /*
2346 * Save FPU state to signal context. Signal handler will "inherit"
2347 * current FPU state.
2348 */
2349 preempt_disable();
2350
2351 if (!is_fpu_owner()) {
2352 own_fpu();
2353 restore_fp(current);
2354 }
2355 err |= save_fp_context(sc);
2356
2357 preempt_enable();
2358 out:
2359#endif
2360 return err;
2361}
2362
2363static inline int
2364restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2365{
2366 int err = 0;
2367
2368 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2369
thsb5dc7732008-06-27 10:02:35 +00002370 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2371 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002372
thsead93602007-09-06 00:18:15 +00002373#define restore_gp_reg(i) do { \
thsb5dc7732008-06-27 10:02:35 +00002374 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002375 } while(0)
2376 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
2377 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
2378 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
2379 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
2380 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
2381 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
2382 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
2383 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
2384 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
2385 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
2386 restore_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002387#undef restore_gp_reg
bellard106ec872006-06-27 21:08:10 +00002388
2389#if 0
2390 if (cpu_has_dsp) {
2391 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
2392 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
2393 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
2394 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
2395 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
2396 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2397 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2398 }
ths388bb212007-05-13 13:58:00 +00002399#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002400 err |= __get_user(regs->hi, &sc->sc_hi[0]);
2401 err |= __get_user(regs->lo, &sc->sc_lo[0]);
2402 if (cpu_has_dsp) {
2403 err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
2404 err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
2405 err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
2406 err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
2407 err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
2408 err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
2409 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2410 }
ths388bb212007-05-13 13:58:00 +00002411#endif
bellard106ec872006-06-27 21:08:10 +00002412
2413 err |= __get_user(used_math, &sc->sc_used_math);
2414 conditional_used_math(used_math);
2415
2416 preempt_disable();
2417
2418 if (used_math()) {
2419 /* restore fpu context if we have used it before */
2420 own_fpu();
2421 err |= restore_fp_context(sc);
2422 } else {
2423 /* signal handler may have used FPU. Give it up. */
2424 lose_fpu();
2425 }
2426
2427 preempt_enable();
2428#endif
2429 return err;
2430}
2431/*
2432 * Determine which stack to use..
2433 */
bellard579a97f2007-11-11 14:26:47 +00002434static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00002435get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002436{
2437 unsigned long sp;
2438
2439 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002440 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002441
2442 /*
2443 * FPU emulator may have it's own trampoline active just
2444 * above the user stack, 16-bytes before the next lowest
2445 * 16 byte boundary. Try to avoid trashing it.
2446 */
2447 sp -= 32;
2448
bellard106ec872006-06-27 21:08:10 +00002449 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002450 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002451 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2452 }
bellard106ec872006-06-27 21:08:10 +00002453
bellard579a97f2007-11-11 14:26:47 +00002454 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002455}
2456
bellard579a97f2007-11-11 14:26:47 +00002457/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002458static void setup_frame(int sig, struct target_sigaction * ka,
bellard579a97f2007-11-11 14:26:47 +00002459 target_sigset_t *set, CPUState *regs)
bellard106ec872006-06-27 21:08:10 +00002460{
2461 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002462 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002463 int i;
2464
bellard579a97f2007-11-11 14:26:47 +00002465 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2466 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002467 goto give_sigsegv;
2468
2469 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2470
2471 if(setup_sigcontext(regs, &frame->sf_sc))
2472 goto give_sigsegv;
2473
2474 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2475 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2476 goto give_sigsegv;
2477 }
2478
2479 /*
2480 * Arguments to signal handler:
2481 *
2482 * a0 = signal number
2483 * a1 = 0 (should be cause)
2484 * a2 = pointer to struct sigcontext
2485 *
2486 * $25 and PC point to the signal handler, $29 points to the
2487 * struct sigframe.
2488 */
thsb5dc7732008-06-27 10:02:35 +00002489 regs->active_tc.gpr[ 4] = sig;
2490 regs->active_tc.gpr[ 5] = 0;
2491 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2492 regs->active_tc.gpr[29] = frame_addr;
2493 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002494 /* The original kernel code sets CP0_EPC to the handler
2495 * since it returns to userland using eret
2496 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002497 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
bellard579a97f2007-11-11 14:26:47 +00002498 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002499 return;
2500
2501give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002502 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002503 force_sig(TARGET_SIGSEGV/*, current*/);
ths5fafdf22007-09-16 21:08:06 +00002504 return;
bellard106ec872006-06-27 21:08:10 +00002505}
2506
2507long do_sigreturn(CPUState *regs)
2508{
ths388bb212007-05-13 13:58:00 +00002509 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002510 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002511 sigset_t blocked;
2512 target_sigset_t target_set;
2513 int i;
bellard106ec872006-06-27 21:08:10 +00002514
2515#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002516 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002517#endif
thsb5dc7732008-06-27 10:02:35 +00002518 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002519 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002520 goto badframe;
2521
ths388bb212007-05-13 13:58:00 +00002522 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002523 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2524 goto badframe;
ths388bb212007-05-13 13:58:00 +00002525 }
bellard106ec872006-06-27 21:08:10 +00002526
ths388bb212007-05-13 13:58:00 +00002527 target_to_host_sigset_internal(&blocked, &target_set);
2528 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002529
ths388bb212007-05-13 13:58:00 +00002530 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002531 goto badframe;
2532
2533#if 0
ths388bb212007-05-13 13:58:00 +00002534 /*
2535 * Don't let your children do this ...
2536 */
2537 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002538 "move\t$29, %0\n\t"
2539 "j\tsyscall_exit"
2540 :/* no outputs */
2541 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002542 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002543#endif
ths3b46e622007-09-17 08:09:54 +00002544
thsb5dc7732008-06-27 10:02:35 +00002545 regs->active_tc.PC = regs->CP0_EPC;
ths388bb212007-05-13 13:58:00 +00002546 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002547 * maybe a problem with nested signals ? */
2548 regs->CP0_EPC = 0;
2549 return 0;
2550
2551badframe:
ths388bb212007-05-13 13:58:00 +00002552 force_sig(TARGET_SIGSEGV/*, current*/);
2553 return 0;
bellard106ec872006-06-27 21:08:10 +00002554}
2555
pbrook624f7972008-05-31 16:11:38 +00002556static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard106ec872006-06-27 21:08:10 +00002557 target_siginfo_t *info,
2558 target_sigset_t *set, CPUState *env)
2559{
2560 fprintf(stderr, "setup_rt_frame: not implemented\n");
2561}
2562
2563long do_rt_sigreturn(CPUState *env)
2564{
2565 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002566 return -TARGET_ENOSYS;
bellard106ec872006-06-27 21:08:10 +00002567}
bellard6d5e2162004-09-30 22:04:13 +00002568
thsc3b5bc82007-12-02 06:31:25 +00002569#elif defined(TARGET_SH4)
2570
2571/*
2572 * code and data structures from linux kernel:
2573 * include/asm-sh/sigcontext.h
2574 * arch/sh/kernel/signal.c
2575 */
2576
2577struct target_sigcontext {
2578 target_ulong oldmask;
2579
2580 /* CPU registers */
2581 target_ulong sc_gregs[16];
2582 target_ulong sc_pc;
2583 target_ulong sc_pr;
2584 target_ulong sc_sr;
2585 target_ulong sc_gbr;
2586 target_ulong sc_mach;
2587 target_ulong sc_macl;
2588
2589 /* FPU registers */
2590 target_ulong sc_fpregs[16];
2591 target_ulong sc_xfpregs[16];
2592 unsigned int sc_fpscr;
2593 unsigned int sc_fpul;
2594 unsigned int sc_ownedfp;
2595};
2596
2597struct target_sigframe
2598{
2599 struct target_sigcontext sc;
2600 target_ulong extramask[TARGET_NSIG_WORDS-1];
2601 uint16_t retcode[3];
2602};
2603
2604
2605struct target_ucontext {
2606 target_ulong uc_flags;
2607 struct target_ucontext *uc_link;
2608 target_stack_t uc_stack;
2609 struct target_sigcontext uc_mcontext;
2610 target_sigset_t uc_sigmask; /* mask last for extensibility */
2611};
2612
2613struct target_rt_sigframe
2614{
2615 struct target_siginfo info;
2616 struct target_ucontext uc;
2617 uint16_t retcode[3];
2618};
2619
2620
2621#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
2622#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
2623
pbrook624f7972008-05-31 16:11:38 +00002624static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002625 unsigned long sp, size_t frame_size)
2626{
pbrook624f7972008-05-31 16:11:38 +00002627 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00002628 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2629 }
2630
2631 return (sp - frame_size) & -8ul;
2632}
2633
2634static int setup_sigcontext(struct target_sigcontext *sc,
2635 CPUState *regs, unsigned long mask)
2636{
2637 int err = 0;
2638
2639#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
2640 COPY(gregs[0]); COPY(gregs[1]);
2641 COPY(gregs[2]); COPY(gregs[3]);
2642 COPY(gregs[4]); COPY(gregs[5]);
2643 COPY(gregs[6]); COPY(gregs[7]);
2644 COPY(gregs[8]); COPY(gregs[9]);
2645 COPY(gregs[10]); COPY(gregs[11]);
2646 COPY(gregs[12]); COPY(gregs[13]);
2647 COPY(gregs[14]); COPY(gregs[15]);
2648 COPY(gbr); COPY(mach);
2649 COPY(macl); COPY(pr);
2650 COPY(sr); COPY(pc);
2651#undef COPY
2652
2653 /* todo: save FPU registers here */
2654
2655 /* non-iBCS2 extensions.. */
2656 err |= __put_user(mask, &sc->oldmask);
2657
2658 return err;
2659}
2660
2661static int restore_sigcontext(struct CPUState *regs,
2662 struct target_sigcontext *sc)
2663{
2664 unsigned int err = 0;
2665
2666#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
2667 COPY(gregs[1]);
2668 COPY(gregs[2]); COPY(gregs[3]);
2669 COPY(gregs[4]); COPY(gregs[5]);
2670 COPY(gregs[6]); COPY(gregs[7]);
2671 COPY(gregs[8]); COPY(gregs[9]);
2672 COPY(gregs[10]); COPY(gregs[11]);
2673 COPY(gregs[12]); COPY(gregs[13]);
2674 COPY(gregs[14]); COPY(gregs[15]);
2675 COPY(gbr); COPY(mach);
2676 COPY(macl); COPY(pr);
2677 COPY(sr); COPY(pc);
2678#undef COPY
2679
2680 /* todo: restore FPU registers here */
2681
2682 regs->tra = -1; /* disable syscall checks */
2683 return err;
2684}
2685
pbrook624f7972008-05-31 16:11:38 +00002686static void setup_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002687 target_sigset_t *set, CPUState *regs)
2688{
2689 struct target_sigframe *frame;
2690 abi_ulong frame_addr;
2691 int i;
2692 int err = 0;
2693 int signal;
2694
2695 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2696 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2697 goto give_sigsegv;
2698
2699 signal = current_exec_domain_sig(sig);
2700
2701 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
2702
2703 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2704 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
2705 }
2706
2707 /* Set up to return from userspace. If provided, use a stub
2708 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002709 if (ka->sa_flags & TARGET_SA_RESTORER) {
2710 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002711 } else {
2712 /* Generate return code (system call to sigreturn) */
2713 err |= __put_user(MOVW(2), &frame->retcode[0]);
2714 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2715 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
2716 regs->pr = (unsigned long) frame->retcode;
2717 }
2718
2719 if (err)
2720 goto give_sigsegv;
2721
2722 /* Set up registers for signal handler */
2723 regs->gregs[15] = (unsigned long) frame;
2724 regs->gregs[4] = signal; /* Arg for signal handler */
2725 regs->gregs[5] = 0;
2726 regs->gregs[6] = (unsigned long) &frame->sc;
pbrook624f7972008-05-31 16:11:38 +00002727 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002728
2729 unlock_user_struct(frame, frame_addr, 1);
2730 return;
2731
2732give_sigsegv:
2733 unlock_user_struct(frame, frame_addr, 1);
2734 force_sig(SIGSEGV);
2735}
2736
pbrook624f7972008-05-31 16:11:38 +00002737static void setup_rt_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002738 target_siginfo_t *info,
2739 target_sigset_t *set, CPUState *regs)
2740{
2741 struct target_rt_sigframe *frame;
2742 abi_ulong frame_addr;
2743 int i;
2744 int err = 0;
2745 int signal;
2746
2747 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2748 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2749 goto give_sigsegv;
2750
2751 signal = current_exec_domain_sig(sig);
2752
2753 err |= copy_siginfo_to_user(&frame->info, info);
2754
2755 /* Create the ucontext. */
2756 err |= __put_user(0, &frame->uc.uc_flags);
2757 err |= __put_user(0, (unsigned long *)&frame->uc.uc_link);
balrog526ccb72008-07-16 12:13:52 +00002758 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
thsc3b5bc82007-12-02 06:31:25 +00002759 &frame->uc.uc_stack.ss_sp);
2760 err |= __put_user(sas_ss_flags(regs->gregs[15]),
2761 &frame->uc.uc_stack.ss_flags);
2762 err |= __put_user(target_sigaltstack_used.ss_size,
2763 &frame->uc.uc_stack.ss_size);
2764 err |= setup_sigcontext(&frame->uc.uc_mcontext,
2765 regs, set->sig[0]);
2766 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2767 err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]);
2768 }
2769
2770 /* Set up to return from userspace. If provided, use a stub
2771 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002772 if (ka->sa_flags & TARGET_SA_RESTORER) {
2773 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002774 } else {
2775 /* Generate return code (system call to sigreturn) */
2776 err |= __put_user(MOVW(2), &frame->retcode[0]);
2777 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2778 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
2779 regs->pr = (unsigned long) frame->retcode;
2780 }
2781
2782 if (err)
2783 goto give_sigsegv;
2784
2785 /* Set up registers for signal handler */
2786 regs->gregs[15] = (unsigned long) frame;
2787 regs->gregs[4] = signal; /* Arg for signal handler */
2788 regs->gregs[5] = (unsigned long) &frame->info;
2789 regs->gregs[6] = (unsigned long) &frame->uc;
pbrook624f7972008-05-31 16:11:38 +00002790 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002791
2792 unlock_user_struct(frame, frame_addr, 1);
2793 return;
2794
2795give_sigsegv:
2796 unlock_user_struct(frame, frame_addr, 1);
2797 force_sig(SIGSEGV);
2798}
2799
2800long do_sigreturn(CPUState *regs)
2801{
2802 struct target_sigframe *frame;
2803 abi_ulong frame_addr;
2804 sigset_t blocked;
2805 target_sigset_t target_set;
2806 int i;
2807 int err = 0;
2808
2809#if defined(DEBUG_SIGNAL)
2810 fprintf(stderr, "do_sigreturn\n");
2811#endif
2812 frame_addr = regs->gregs[15];
2813 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2814 goto badframe;
2815
2816 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
2817 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2818 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
2819 }
2820
2821 if (err)
2822 goto badframe;
2823
2824 target_to_host_sigset_internal(&blocked, &target_set);
2825 sigprocmask(SIG_SETMASK, &blocked, NULL);
2826
2827 if (restore_sigcontext(regs, &frame->sc))
2828 goto badframe;
2829
2830 unlock_user_struct(frame, frame_addr, 0);
2831 return regs->gregs[0];
2832
2833badframe:
2834 unlock_user_struct(frame, frame_addr, 0);
2835 force_sig(TARGET_SIGSEGV);
2836 return 0;
2837}
2838
2839long do_rt_sigreturn(CPUState *regs)
2840{
2841 struct target_rt_sigframe *frame;
2842 abi_ulong frame_addr;
2843 sigset_t blocked;
2844
2845#if defined(DEBUG_SIGNAL)
2846 fprintf(stderr, "do_rt_sigreturn\n");
2847#endif
2848 frame_addr = regs->gregs[15];
2849 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2850 goto badframe;
2851
2852 target_to_host_sigset(&blocked, &frame->uc.uc_sigmask);
2853 sigprocmask(SIG_SETMASK, &blocked, NULL);
2854
2855 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
2856 goto badframe;
2857
2858 if (do_sigaltstack(frame_addr +
2859 offsetof(struct target_rt_sigframe, uc.uc_stack),
2860 0, get_sp_from_cpustate(regs)) == -EFAULT)
2861 goto badframe;
2862
2863 unlock_user_struct(frame, frame_addr, 0);
2864 return regs->gregs[0];
2865
2866badframe:
2867 unlock_user_struct(frame, frame_addr, 0);
2868 force_sig(TARGET_SIGSEGV);
2869 return 0;
2870}
edgar_iglb6d3abd2008-02-28 11:29:27 +00002871#elif defined(TARGET_CRIS)
2872
2873struct target_sigcontext {
2874 struct target_pt_regs regs; /* needs to be first */
2875 uint32_t oldmask;
2876 uint32_t usp; /* usp before stacking this gunk on it */
2877};
2878
2879/* Signal frames. */
2880struct target_signal_frame {
2881 struct target_sigcontext sc;
2882 uint32_t extramask[TARGET_NSIG_WORDS - 1];
2883 uint8_t retcode[8]; /* Trampoline code. */
2884};
2885
2886struct rt_signal_frame {
2887 struct siginfo *pinfo;
2888 void *puc;
2889 struct siginfo info;
2890 struct ucontext uc;
2891 uint8_t retcode[8]; /* Trampoline code. */
2892};
2893
2894static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
2895{
edgar_igl9664d922008-03-03 22:23:53 +00002896 __put_user(env->regs[0], &sc->regs.r0);
2897 __put_user(env->regs[1], &sc->regs.r1);
2898 __put_user(env->regs[2], &sc->regs.r2);
2899 __put_user(env->regs[3], &sc->regs.r3);
2900 __put_user(env->regs[4], &sc->regs.r4);
2901 __put_user(env->regs[5], &sc->regs.r5);
2902 __put_user(env->regs[6], &sc->regs.r6);
2903 __put_user(env->regs[7], &sc->regs.r7);
2904 __put_user(env->regs[8], &sc->regs.r8);
2905 __put_user(env->regs[9], &sc->regs.r9);
2906 __put_user(env->regs[10], &sc->regs.r10);
2907 __put_user(env->regs[11], &sc->regs.r11);
2908 __put_user(env->regs[12], &sc->regs.r12);
2909 __put_user(env->regs[13], &sc->regs.r13);
2910 __put_user(env->regs[14], &sc->usp);
2911 __put_user(env->regs[15], &sc->regs.acr);
2912 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
2913 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
2914 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002915}
edgar_igl9664d922008-03-03 22:23:53 +00002916
edgar_iglb6d3abd2008-02-28 11:29:27 +00002917static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
2918{
edgar_igl9664d922008-03-03 22:23:53 +00002919 __get_user(env->regs[0], &sc->regs.r0);
2920 __get_user(env->regs[1], &sc->regs.r1);
2921 __get_user(env->regs[2], &sc->regs.r2);
2922 __get_user(env->regs[3], &sc->regs.r3);
2923 __get_user(env->regs[4], &sc->regs.r4);
2924 __get_user(env->regs[5], &sc->regs.r5);
2925 __get_user(env->regs[6], &sc->regs.r6);
2926 __get_user(env->regs[7], &sc->regs.r7);
2927 __get_user(env->regs[8], &sc->regs.r8);
2928 __get_user(env->regs[9], &sc->regs.r9);
2929 __get_user(env->regs[10], &sc->regs.r10);
2930 __get_user(env->regs[11], &sc->regs.r11);
2931 __get_user(env->regs[12], &sc->regs.r12);
2932 __get_user(env->regs[13], &sc->regs.r13);
2933 __get_user(env->regs[14], &sc->usp);
2934 __get_user(env->regs[15], &sc->regs.acr);
2935 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
2936 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
2937 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002938}
2939
edgar_igl9664d922008-03-03 22:23:53 +00002940static abi_ulong get_sigframe(CPUState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00002941{
edgar_igl9664d922008-03-03 22:23:53 +00002942 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002943 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00002944 sp = (env->regs[R_SP] & ~3);
2945 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002946}
2947
pbrook624f7972008-05-31 16:11:38 +00002948static void setup_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00002949 target_sigset_t *set, CPUState *env)
2950{
2951 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00002952 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002953 int err = 0;
2954 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002955
edgar_igl9664d922008-03-03 22:23:53 +00002956 frame_addr = get_sigframe(env, sizeof *frame);
2957 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00002958 goto badframe;
2959
2960 /*
2961 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
2962 * use this trampoline anymore but it sets it up for GDB.
2963 * In QEMU, using the trampoline simplifies things a bit so we use it.
2964 *
2965 * This is movu.w __NR_sigreturn, r9; break 13;
2966 */
2967 err |= __put_user(0x9c5f, frame->retcode+0);
2968 err |= __put_user(TARGET_NR_sigreturn,
2969 frame->retcode+2);
2970 err |= __put_user(0xe93d, frame->retcode+4);
2971
2972 /* Save the mask. */
2973 err |= __put_user(set->sig[0], &frame->sc.oldmask);
2974 if (err)
2975 goto badframe;
2976
2977 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2978 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
2979 goto badframe;
2980 }
2981
2982 setup_sigcontext(&frame->sc, env);
2983
2984 /* Move the stack and setup the arguments for the handler. */
balrog526ccb72008-07-16 12:13:52 +00002985 env->regs[R_SP] = (uint32_t) (unsigned long) frame;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002986 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00002987 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002988 /* Link SRP so the guest returns through the trampoline. */
balrog526ccb72008-07-16 12:13:52 +00002989 env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
edgar_iglb6d3abd2008-02-28 11:29:27 +00002990
edgar_igl9664d922008-03-03 22:23:53 +00002991 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002992 return;
2993 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00002994 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002995 force_sig(TARGET_SIGSEGV);
2996}
2997
pbrook624f7972008-05-31 16:11:38 +00002998static void setup_rt_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00002999 target_siginfo_t *info,
3000 target_sigset_t *set, CPUState *env)
3001{
3002 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3003}
3004
3005long do_sigreturn(CPUState *env)
3006{
3007 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003008 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003009 target_sigset_t target_set;
3010 sigset_t set;
3011 int i;
3012
edgar_igl9664d922008-03-03 22:23:53 +00003013 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003014 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003015 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003016 goto badframe;
3017
3018 /* Restore blocked signals */
3019 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3020 goto badframe;
3021 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3022 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3023 goto badframe;
3024 }
3025 target_to_host_sigset_internal(&set, &target_set);
3026 sigprocmask(SIG_SETMASK, &set, NULL);
3027
3028 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003029 /* Compensate for the syscall return path advancing brk. */
3030 env->pc -= 2;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003031
edgar_igl9664d922008-03-03 22:23:53 +00003032 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003033 return env->regs[10];
3034 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003035 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003036 force_sig(TARGET_SIGSEGV);
3037}
3038
3039long do_rt_sigreturn(CPUState *env)
3040{
3041 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3042 return -TARGET_ENOSYS;
3043}
thsc3b5bc82007-12-02 06:31:25 +00003044
bellardb346ff42003-06-15 20:05:50 +00003045#else
3046
pbrook624f7972008-05-31 16:11:38 +00003047static void setup_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003048 target_sigset_t *set, CPUState *env)
3049{
3050 fprintf(stderr, "setup_frame: not implemented\n");
3051}
3052
pbrook624f7972008-05-31 16:11:38 +00003053static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003054 target_siginfo_t *info,
3055 target_sigset_t *set, CPUState *env)
3056{
3057 fprintf(stderr, "setup_rt_frame: not implemented\n");
3058}
3059
3060long do_sigreturn(CPUState *env)
3061{
3062 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003063 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003064}
3065
3066long do_rt_sigreturn(CPUState *env)
3067{
3068 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003069 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003070}
3071
bellard66fb9762003-03-23 01:06:05 +00003072#endif
3073
pbrook624f7972008-05-31 16:11:38 +00003074void process_pending_signals(CPUState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00003075{
3076 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00003077 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00003078 sigset_t set, old_set;
3079 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00003080 struct emulated_sigtable *k;
3081 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00003082 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00003083 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00003084
pbrook624f7972008-05-31 16:11:38 +00003085 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00003086 return;
3087
pbrook624f7972008-05-31 16:11:38 +00003088 /* FIXME: This is not threadsafe. */
3089 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00003090 for(sig = 1; sig <= TARGET_NSIG; sig++) {
3091 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00003092 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00003093 k++;
bellard31e31b82003-02-18 22:55:36 +00003094 }
3095 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00003096 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00003097 return;
bellard66fb9762003-03-23 01:06:05 +00003098
bellard31e31b82003-02-18 22:55:36 +00003099 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00003100#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00003101 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00003102#endif
3103 /* dequeue signal */
3104 q = k->first;
3105 k->first = q->next;
3106 if (!k->first)
3107 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00003108
bellard1fddef42005-04-17 19:16:13 +00003109 sig = gdb_handlesig (cpu_env, sig);
3110 if (!sig) {
3111 fprintf (stderr, "Lost signal\n");
3112 abort();
3113 }
bellard66fb9762003-03-23 01:06:05 +00003114
pbrook624f7972008-05-31 16:11:38 +00003115 sa = &sigact_table[sig - 1];
3116 handler = sa->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00003117 if (handler == TARGET_SIG_DFL) {
3118 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +00003119 if (sig != TARGET_SIGCHLD &&
3120 sig != TARGET_SIGURG &&
bellard66fb9762003-03-23 01:06:05 +00003121 sig != TARGET_SIGWINCH) {
3122 force_sig(sig);
3123 }
3124 } else if (handler == TARGET_SIG_IGN) {
3125 /* ignore sig */
3126 } else if (handler == TARGET_SIG_ERR) {
3127 force_sig(sig);
3128 } else {
bellard9de5e442003-03-23 16:49:39 +00003129 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00003130 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00003131 /* SA_NODEFER indicates that the current signal should not be
3132 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00003133 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00003134 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00003135
bellard9de5e442003-03-23 16:49:39 +00003136 /* block signals in the handler using Linux */
3137 sigprocmask(SIG_BLOCK, &set, &old_set);
3138 /* save the previous blocked signal state to restore it at the
3139 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00003140 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00003141
bellardbc8a22c2003-03-30 21:02:40 +00003142 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00003143#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00003144 {
3145 CPUX86State *env = cpu_env;
3146 if (env->eflags & VM_MASK)
3147 save_v86_state(env);
3148 }
3149#endif
bellard9de5e442003-03-23 16:49:39 +00003150 /* prepare the stack frame of the virtual CPU */
pbrook624f7972008-05-31 16:11:38 +00003151 if (sa->sa_flags & TARGET_SA_SIGINFO)
3152 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00003153 else
pbrook624f7972008-05-31 16:11:38 +00003154 setup_frame(sig, sa, &target_old_set, cpu_env);
3155 if (sa->sa_flags & TARGET_SA_RESETHAND)
3156 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00003157 }
bellard66fb9762003-03-23 01:06:05 +00003158 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00003159 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00003160}