blob: 75047251bb23d55bc13decdcb75042c1cdcce9d8 [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
blueswir1530e7612009-01-05 18:11:53 +000018 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 * MA 02110-1301, USA.
bellard31e31b82003-02-18 22:55:36 +000020 */
21#include <stdlib.h>
22#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000023#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000025#include <unistd.h>
bellard31e31b82003-02-18 22:55:36 +000026#include <signal.h>
bellard66fb9762003-03-23 01:06:05 +000027#include <errno.h>
aurel32603e4fd2009-04-15 16:18:38 +000028#include <assert.h>
bellard31e31b82003-02-18 22:55:36 +000029#include <sys/ucontext.h>
30
bellard3ef693a2003-03-23 20:17:16 +000031#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000032#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000033#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000034
35//#define DEBUG_SIGNAL
36
blueswir1249c4c32008-10-05 11:09:37 +000037static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000038 .ss_sp = 0,
39 .ss_size = 0,
40 .ss_flags = TARGET_SS_DISABLE,
41};
42
pbrook624f7972008-05-31 16:11:38 +000043static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000044
ths5fafdf22007-09-16 21:08:06 +000045static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000046 void *puc);
47
bellard9e5f5282003-07-13 17:33:54 +000048static uint8_t host_to_target_signal_table[65] = {
49 [SIGHUP] = TARGET_SIGHUP,
50 [SIGINT] = TARGET_SIGINT,
51 [SIGQUIT] = TARGET_SIGQUIT,
52 [SIGILL] = TARGET_SIGILL,
53 [SIGTRAP] = TARGET_SIGTRAP,
54 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000055/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000056 [SIGBUS] = TARGET_SIGBUS,
57 [SIGFPE] = TARGET_SIGFPE,
58 [SIGKILL] = TARGET_SIGKILL,
59 [SIGUSR1] = TARGET_SIGUSR1,
60 [SIGSEGV] = TARGET_SIGSEGV,
61 [SIGUSR2] = TARGET_SIGUSR2,
62 [SIGPIPE] = TARGET_SIGPIPE,
63 [SIGALRM] = TARGET_SIGALRM,
64 [SIGTERM] = TARGET_SIGTERM,
65#ifdef SIGSTKFLT
66 [SIGSTKFLT] = TARGET_SIGSTKFLT,
67#endif
68 [SIGCHLD] = TARGET_SIGCHLD,
69 [SIGCONT] = TARGET_SIGCONT,
70 [SIGSTOP] = TARGET_SIGSTOP,
71 [SIGTSTP] = TARGET_SIGTSTP,
72 [SIGTTIN] = TARGET_SIGTTIN,
73 [SIGTTOU] = TARGET_SIGTTOU,
74 [SIGURG] = TARGET_SIGURG,
75 [SIGXCPU] = TARGET_SIGXCPU,
76 [SIGXFSZ] = TARGET_SIGXFSZ,
77 [SIGVTALRM] = TARGET_SIGVTALRM,
78 [SIGPROF] = TARGET_SIGPROF,
79 [SIGWINCH] = TARGET_SIGWINCH,
80 [SIGIO] = TARGET_SIGIO,
81 [SIGPWR] = TARGET_SIGPWR,
82 [SIGSYS] = TARGET_SIGSYS,
83 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000084 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
85 host libpthread signals. This assumes noone actually uses SIGRTMAX :-/
86 To fix this properly we need to do manual signal delivery multiplexed
87 over a single host signal. */
88 [__SIGRTMIN] = __SIGRTMAX,
89 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000090};
91static uint8_t target_to_host_signal_table[65];
92
thsa04e1342007-09-27 13:57:58 +000093static inline int on_sig_stack(unsigned long sp)
94{
95 return (sp - target_sigaltstack_used.ss_sp
96 < target_sigaltstack_used.ss_size);
97}
98
99static inline int sas_ss_flags(unsigned long sp)
100{
101 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
102 : on_sig_stack(sp) ? SS_ONSTACK : 0);
103}
104
bellard31e31b82003-02-18 22:55:36 +0000105static inline int host_to_target_signal(int sig)
106{
pbrook4cb05962008-05-30 18:05:19 +0000107 if (sig > 64)
108 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000109 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000110}
111
pbrook4cb05962008-05-30 18:05:19 +0000112int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000113{
pbrook4cb05962008-05-30 18:05:19 +0000114 if (sig > 64)
115 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000116 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000117}
118
pbrookf5545b52008-05-30 22:37:07 +0000119static inline void target_sigemptyset(target_sigset_t *set)
120{
121 memset(set, 0, sizeof(*set));
122}
123
124static inline void target_sigaddset(target_sigset_t *set, int signum)
125{
126 signum--;
127 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
128 set->sig[signum / TARGET_NSIG_BPW] |= mask;
129}
130
131static inline int target_sigismember(const target_sigset_t *set, int signum)
132{
133 signum--;
134 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
135 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
136}
137
ths5fafdf22007-09-16 21:08:06 +0000138static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000139 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000140{
141 int i;
pbrookf5545b52008-05-30 22:37:07 +0000142 target_sigemptyset(d);
143 for (i = 1; i <= TARGET_NSIG; i++) {
144 if (sigismember(s, i)) {
145 target_sigaddset(d, host_to_target_signal(i));
146 }
bellard9e5f5282003-07-13 17:33:54 +0000147 }
bellard66fb9762003-03-23 01:06:05 +0000148}
149
bellard92319442004-06-19 16:58:13 +0000150void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
151{
152 target_sigset_t d1;
153 int i;
154
155 host_to_target_sigset_internal(&d1, s);
156 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000157 d->sig[i] = tswapl(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000158}
159
blueswir18fcd3692008-08-17 20:26:25 +0000160static void target_to_host_sigset_internal(sigset_t *d,
161 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000162{
163 int i;
pbrookf5545b52008-05-30 22:37:07 +0000164 sigemptyset(d);
165 for (i = 1; i <= TARGET_NSIG; i++) {
166 if (target_sigismember(s, i)) {
167 sigaddset(d, target_to_host_signal(i));
168 }
169 }
bellard66fb9762003-03-23 01:06:05 +0000170}
171
bellard92319442004-06-19 16:58:13 +0000172void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
173{
174 target_sigset_t s1;
175 int i;
176
177 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000178 s1.sig[i] = tswapl(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000179 target_to_host_sigset_internal(d, &s1);
180}
ths3b46e622007-09-17 08:09:54 +0000181
blueswir1992f48a2007-10-14 16:27:31 +0000182void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000183 const sigset_t *sigset)
184{
bellard9e5f5282003-07-13 17:33:54 +0000185 target_sigset_t d;
186 host_to_target_sigset(&d, sigset);
187 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000188}
189
ths5fafdf22007-09-16 21:08:06 +0000190void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000191 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000192{
bellard9e5f5282003-07-13 17:33:54 +0000193 target_sigset_t d;
194 int i;
195
196 d.sig[0] = *old_sigset;
197 for(i = 1;i < TARGET_NSIG_WORDS; i++)
198 d.sig[i] = 0;
199 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000200}
201
bellard9de5e442003-03-23 16:49:39 +0000202/* siginfo conversion */
203
ths5fafdf22007-09-16 21:08:06 +0000204static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000205 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000206{
bellard9de5e442003-03-23 16:49:39 +0000207 int sig;
208 sig = host_to_target_signal(info->si_signo);
209 tinfo->si_signo = sig;
210 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000211 tinfo->si_code = info->si_code;
ths5fafdf22007-09-16 21:08:06 +0000212 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000213 sig == SIGBUS || sig == SIGTRAP) {
bellard9de5e442003-03-23 16:49:39 +0000214 /* should never come here, but who knows. The information for
215 the target is irrelevant */
216 tinfo->_sifields._sigfault._addr = 0;
ths7f7f7c82007-07-12 11:02:46 +0000217 } else if (sig == SIGIO) {
218 tinfo->_sifields._sigpoll._fd = info->si_fd;
bellard9de5e442003-03-23 16:49:39 +0000219 } else if (sig >= TARGET_SIGRTMIN) {
220 tinfo->_sifields._rt._pid = info->si_pid;
221 tinfo->_sifields._rt._uid = info->si_uid;
222 /* XXX: potential problem if 64 bit */
ths5fafdf22007-09-16 21:08:06 +0000223 tinfo->_sifields._rt._sigval.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000224 (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000225 }
bellard66fb9762003-03-23 01:06:05 +0000226}
227
ths5fafdf22007-09-16 21:08:06 +0000228static void tswap_siginfo(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000229 const target_siginfo_t *info)
230{
231 int sig;
232 sig = info->si_signo;
233 tinfo->si_signo = tswap32(sig);
234 tinfo->si_errno = tswap32(info->si_errno);
235 tinfo->si_code = tswap32(info->si_code);
ths5fafdf22007-09-16 21:08:06 +0000236 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000237 sig == SIGBUS || sig == SIGTRAP) {
ths5fafdf22007-09-16 21:08:06 +0000238 tinfo->_sifields._sigfault._addr =
bellard9de5e442003-03-23 16:49:39 +0000239 tswapl(info->_sifields._sigfault._addr);
ths7f7f7c82007-07-12 11:02:46 +0000240 } else if (sig == SIGIO) {
241 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
bellard9de5e442003-03-23 16:49:39 +0000242 } else if (sig >= TARGET_SIGRTMIN) {
243 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
244 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000245 tinfo->_sifields._rt._sigval.sival_ptr =
bellard9de5e442003-03-23 16:49:39 +0000246 tswapl(info->_sifields._rt._sigval.sival_ptr);
247 }
248}
249
250
251void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
252{
253 host_to_target_siginfo_noswap(tinfo, info);
254 tswap_siginfo(tinfo, tinfo);
255}
256
257/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000258/* XXX: find a solution for 64 bit (additional malloced data is needed) */
bellard9de5e442003-03-23 16:49:39 +0000259void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000260{
261 info->si_signo = tswap32(tinfo->si_signo);
262 info->si_errno = tswap32(tinfo->si_errno);
263 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000264 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
265 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000266 info->si_value.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000267 (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000268}
269
aurel32ca587a82008-12-18 22:44:13 +0000270static int fatal_signal (int sig)
271{
272 switch (sig) {
273 case TARGET_SIGCHLD:
274 case TARGET_SIGURG:
275 case TARGET_SIGWINCH:
276 /* Ignored by default. */
277 return 0;
278 case TARGET_SIGCONT:
279 case TARGET_SIGSTOP:
280 case TARGET_SIGTSTP:
281 case TARGET_SIGTTIN:
282 case TARGET_SIGTTOU:
283 /* Job control signals. */
284 return 0;
285 default:
286 return 1;
287 }
288}
289
bellard31e31b82003-02-18 22:55:36 +0000290void signal_init(void)
291{
292 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000293 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000294 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000295 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000296
bellard9e5f5282003-07-13 17:33:54 +0000297 /* generate signal conversion tables */
298 for(i = 1; i <= 64; i++) {
299 if (host_to_target_signal_table[i] == 0)
300 host_to_target_signal_table[i] = i;
301 }
302 for(i = 1; i <= 64; i++) {
303 j = host_to_target_signal_table[i];
304 target_to_host_signal_table[j] = i;
305 }
ths3b46e622007-09-17 08:09:54 +0000306
bellard9de5e442003-03-23 16:49:39 +0000307 /* set all host signal handlers. ALL signals are blocked during
308 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000309 memset(sigact_table, 0, sizeof(sigact_table));
310
bellard9de5e442003-03-23 16:49:39 +0000311 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000312 act.sa_flags = SA_SIGINFO;
313 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000314 for(i = 1; i <= TARGET_NSIG; i++) {
315 host_sig = target_to_host_signal(i);
316 sigaction(host_sig, NULL, &oact);
317 if (oact.sa_sigaction == (void *)SIG_IGN) {
318 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
319 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
320 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
321 }
322 /* If there's already a handler installed then something has
323 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000324 /* Install some handlers for our own use. We need at least
325 SIGSEGV and SIGBUS, to detect exceptions. We can not just
326 trap all signals because it affects syscall interrupt
327 behavior. But do trap all default-fatal signals. */
328 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000329 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000330 }
bellard31e31b82003-02-18 22:55:36 +0000331}
332
bellard66fb9762003-03-23 01:06:05 +0000333/* signal queue handling */
334
pbrook624f7972008-05-31 16:11:38 +0000335static inline struct sigqueue *alloc_sigqueue(CPUState *env)
bellard66fb9762003-03-23 01:06:05 +0000336{
pbrook624f7972008-05-31 16:11:38 +0000337 TaskState *ts = env->opaque;
338 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000339 if (!q)
340 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000341 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000342 return q;
343}
344
pbrook624f7972008-05-31 16:11:38 +0000345static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000346{
pbrook624f7972008-05-31 16:11:38 +0000347 TaskState *ts = env->opaque;
348 q->next = ts->first_free;
349 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000350}
351
bellard9de5e442003-03-23 16:49:39 +0000352/* abort execution with signal */
malca5e50b22009-02-01 22:19:27 +0000353static void QEMU_NORETURN force_sig(int sig)
bellard66fb9762003-03-23 01:06:05 +0000354{
355 int host_sig;
aurel32603e4fd2009-04-15 16:18:38 +0000356 struct sigaction act;
bellard66fb9762003-03-23 01:06:05 +0000357 host_sig = target_to_host_signal(sig);
ths5fafdf22007-09-16 21:08:06 +0000358 fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
bellard66fb9762003-03-23 01:06:05 +0000359 sig, strsignal(host_sig));
aurel32ca587a82008-12-18 22:44:13 +0000360 gdb_signalled(thread_env, sig);
aurel32603e4fd2009-04-15 16:18:38 +0000361
362 /* The proper exit code for dieing from an uncaught signal is
363 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
364 * a negative value. To get the proper exit code we need to
365 * actually die from an uncaught signal. Here the default signal
366 * handler is installed, we send ourself a signal and we wait for
367 * it to arrive. */
368 sigfillset(&act.sa_mask);
369 act.sa_handler = SIG_DFL;
370 sigaction(host_sig, &act, NULL);
371
372 /* For some reason raise(host_sig) doesn't send the signal when
373 * statically linked on x86-64. */
374 kill(getpid(), host_sig);
375
376 /* Make sure the signal isn't masked (just reuse the mask inside
377 of act) */
378 sigdelset(&act.sa_mask, host_sig);
379 sigsuspend(&act.sa_mask);
380
381 /* unreachable */
382 assert(0);
383
bellard66fb9762003-03-23 01:06:05 +0000384}
385
bellard9de5e442003-03-23 16:49:39 +0000386/* queue a signal so that it will be send to the virtual CPU as soon
387 as possible */
pbrook624f7972008-05-31 16:11:38 +0000388int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000389{
pbrook624f7972008-05-31 16:11:38 +0000390 TaskState *ts = env->opaque;
391 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000392 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000393 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000394 int queue;
bellard66fb9762003-03-23 01:06:05 +0000395
bellard9de5e442003-03-23 16:49:39 +0000396#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000397 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000398 sig);
bellard66fb9762003-03-23 01:06:05 +0000399#endif
pbrook624f7972008-05-31 16:11:38 +0000400 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000401 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000402 handler = sigact_table[sig - 1]._sa_handler;
aurel32ca587a82008-12-18 22:44:13 +0000403 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000404 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
405 kill(getpid(),SIGSTOP);
406 return 0;
407 } else
bellard66fb9762003-03-23 01:06:05 +0000408 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000409 if (sig != TARGET_SIGCHLD &&
410 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000411 sig != TARGET_SIGWINCH &&
412 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000413 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000414 } else {
415 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000416 }
aurel32ca587a82008-12-18 22:44:13 +0000417 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000418 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000419 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000420 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000421 force_sig(sig);
422 } else {
bellard9de5e442003-03-23 16:49:39 +0000423 pq = &k->first;
424 if (sig < TARGET_SIGRTMIN) {
425 /* if non real time signal, we queue exactly one signal */
426 if (!k->pending)
427 q = &k->info;
428 else
429 return 0;
430 } else {
431 if (!k->pending) {
432 /* first signal */
433 q = &k->info;
434 } else {
pbrook624f7972008-05-31 16:11:38 +0000435 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000436 if (!q)
437 return -EAGAIN;
438 while (*pq != NULL)
439 pq = &(*pq)->next;
440 }
441 }
442 *pq = q;
443 q->info = *info;
444 q->next = NULL;
445 k->pending = 1;
446 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000447 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000448 return 1; /* indicates that the signal was queued */
449 }
450}
451
ths5fafdf22007-09-16 21:08:06 +0000452static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000453 void *puc)
454{
455 int sig;
456 target_siginfo_t tinfo;
457
458 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000459 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000460 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000461 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000462 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000463 return;
464 }
465
466 /* get target signal number */
467 sig = host_to_target_signal(host_signum);
468 if (sig < 1 || sig > TARGET_NSIG)
469 return;
470#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000471 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000472#endif
473 host_to_target_siginfo_noswap(&tinfo, info);
pbrookd5975362008-06-07 20:50:51 +0000474 if (queue_signal(thread_env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000475 /* interrupt the virtual CPU as soon as possible */
aurel323098dba2009-03-07 21:28:24 +0000476 cpu_exit(thread_env);
bellard66fb9762003-03-23 01:06:05 +0000477 }
bellard31e31b82003-02-18 22:55:36 +0000478}
479
ths0da46a62007-10-20 20:23:07 +0000480/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000481/* compare linux/kernel/signal.c:do_sigaltstack() */
482abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000483{
484 int ret;
485 struct target_sigaltstack oss;
486
487 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000488 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000489 {
490 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
491 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
492 __put_user(sas_ss_flags(sp), &oss.ss_flags);
493 }
494
bellard579a97f2007-11-11 14:26:47 +0000495 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000496 {
bellard579a97f2007-11-11 14:26:47 +0000497 struct target_sigaltstack *uss;
498 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000499
ths0da46a62007-10-20 20:23:07 +0000500 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000501 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000502 || __get_user(ss.ss_sp, &uss->ss_sp)
503 || __get_user(ss.ss_size, &uss->ss_size)
504 || __get_user(ss.ss_flags, &uss->ss_flags))
505 goto out;
bellard579a97f2007-11-11 14:26:47 +0000506 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000507
ths0da46a62007-10-20 20:23:07 +0000508 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000509 if (on_sig_stack(sp))
510 goto out;
511
ths0da46a62007-10-20 20:23:07 +0000512 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000513 if (ss.ss_flags != TARGET_SS_DISABLE
514 && ss.ss_flags != TARGET_SS_ONSTACK
515 && ss.ss_flags != 0)
516 goto out;
517
518 if (ss.ss_flags == TARGET_SS_DISABLE) {
519 ss.ss_size = 0;
520 ss.ss_sp = 0;
521 } else {
ths0da46a62007-10-20 20:23:07 +0000522 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000523 if (ss.ss_size < MINSIGSTKSZ)
524 goto out;
525 }
526
527 target_sigaltstack_used.ss_sp = ss.ss_sp;
528 target_sigaltstack_used.ss_size = ss.ss_size;
529 }
530
bellard579a97f2007-11-11 14:26:47 +0000531 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000532 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000533 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000534 goto out;
thsa04e1342007-09-27 13:57:58 +0000535 }
536
537 ret = 0;
538out:
539 return ret;
540}
541
ths0da46a62007-10-20 20:23:07 +0000542/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000543int do_sigaction(int sig, const struct target_sigaction *act,
544 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000545{
pbrook624f7972008-05-31 16:11:38 +0000546 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000547 struct sigaction act1;
548 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000549 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000550
ths2a913eb2008-11-27 15:46:25 +0000551 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000552 return -EINVAL;
553 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000554#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000555 fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
bellard66fb9762003-03-23 01:06:05 +0000556 sig, (int)act, (int)oact);
557#endif
558 if (oact) {
pbrook624f7972008-05-31 16:11:38 +0000559 oact->_sa_handler = tswapl(k->_sa_handler);
560 oact->sa_flags = tswapl(k->sa_flags);
ths388bb212007-05-13 13:58:00 +0000561#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000562 oact->sa_restorer = tswapl(k->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000563#endif
pbrook624f7972008-05-31 16:11:38 +0000564 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000565 }
566 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000567 /* FIXME: This is not threadsafe. */
568 k->_sa_handler = tswapl(act->_sa_handler);
569 k->sa_flags = tswapl(act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000570#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000571 k->sa_restorer = tswapl(act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000572#endif
pbrook624f7972008-05-31 16:11:38 +0000573 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000574
575 /* we update the host linux signal state */
576 host_sig = target_to_host_signal(sig);
577 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
578 sigfillset(&act1.sa_mask);
579 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000580 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000581 act1.sa_flags |= SA_RESTART;
582 /* NOTE: it is important to update the host kernel signal
583 ignore state to avoid getting unexpected interrupted
584 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000585 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000586 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000587 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000588 if (fatal_signal (sig))
589 act1.sa_sigaction = host_signal_handler;
590 else
591 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000592 } else {
593 act1.sa_sigaction = host_signal_handler;
594 }
ths0da46a62007-10-20 20:23:07 +0000595 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000596 }
bellard66fb9762003-03-23 01:06:05 +0000597 }
ths0da46a62007-10-20 20:23:07 +0000598 return ret;
bellard66fb9762003-03-23 01:06:05 +0000599}
bellard31e31b82003-02-18 22:55:36 +0000600
ths5fafdf22007-09-16 21:08:06 +0000601static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
bellard43fff232003-07-09 19:31:39 +0000602 const target_siginfo_t *info)
603{
604 tswap_siginfo(tinfo, info);
605 return 0;
606}
607
thsc3b5bc82007-12-02 06:31:25 +0000608static inline int current_exec_domain_sig(int sig)
609{
610 return /* current->exec_domain && current->exec_domain->signal_invmap
611 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
612}
613
bellard459a4012007-11-11 19:45:10 +0000614#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000615
616/* from the Linux kernel */
617
618struct target_fpreg {
619 uint16_t significand[4];
620 uint16_t exponent;
621};
622
623struct target_fpxreg {
624 uint16_t significand[4];
625 uint16_t exponent;
626 uint16_t padding[3];
627};
628
629struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000630 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000631};
632
633struct target_fpstate {
634 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000635 abi_ulong cw;
636 abi_ulong sw;
637 abi_ulong tag;
638 abi_ulong ipoff;
639 abi_ulong cssel;
640 abi_ulong dataoff;
641 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000642 struct target_fpreg _st[8];
643 uint16_t status;
644 uint16_t magic; /* 0xffff = regular FPU data only */
645
646 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000647 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
648 abi_ulong mxcsr;
649 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000650 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
651 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000652 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000653};
654
655#define X86_FXSR_MAGIC 0x0000
656
657struct target_sigcontext {
658 uint16_t gs, __gsh;
659 uint16_t fs, __fsh;
660 uint16_t es, __esh;
661 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000662 abi_ulong edi;
663 abi_ulong esi;
664 abi_ulong ebp;
665 abi_ulong esp;
666 abi_ulong ebx;
667 abi_ulong edx;
668 abi_ulong ecx;
669 abi_ulong eax;
670 abi_ulong trapno;
671 abi_ulong err;
672 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000673 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000674 abi_ulong eflags;
675 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000676 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000677 abi_ulong fpstate; /* pointer */
678 abi_ulong oldmask;
679 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000680};
681
bellard66fb9762003-03-23 01:06:05 +0000682struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000683 abi_ulong tuc_flags;
684 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +0000685 target_stack_t tuc_stack;
686 struct target_sigcontext tuc_mcontext;
687 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000688};
689
690struct sigframe
691{
blueswir1992f48a2007-10-14 16:27:31 +0000692 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000693 int sig;
694 struct target_sigcontext sc;
695 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000696 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000697 char retcode[8];
698};
699
700struct rt_sigframe
701{
blueswir1992f48a2007-10-14 16:27:31 +0000702 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000703 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000704 abi_ulong pinfo;
705 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000706 struct target_siginfo info;
707 struct target_ucontext uc;
708 struct target_fpstate fpstate;
709 char retcode[8];
710};
711
712/*
713 * Set up a signal frame.
714 */
715
bellard66fb9762003-03-23 01:06:05 +0000716/* XXX: save x87 state */
717static int
718setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000719 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000720{
721 int err = 0;
bellard775b58d2007-11-11 16:22:17 +0000722 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000723
bellard579a97f2007-11-11 14:26:47 +0000724 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000725 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
726 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
727 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
728 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000729 err |= __put_user(env->regs[R_EDI], &sc->edi);
730 err |= __put_user(env->regs[R_ESI], &sc->esi);
731 err |= __put_user(env->regs[R_EBP], &sc->ebp);
732 err |= __put_user(env->regs[R_ESP], &sc->esp);
733 err |= __put_user(env->regs[R_EBX], &sc->ebx);
734 err |= __put_user(env->regs[R_EDX], &sc->edx);
735 err |= __put_user(env->regs[R_ECX], &sc->ecx);
736 err |= __put_user(env->regs[R_EAX], &sc->eax);
bellard66099dd2003-05-08 15:34:02 +0000737 err |= __put_user(env->exception_index, &sc->trapno);
738 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000739 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000740 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000741 err |= __put_user(env->eflags, &sc->eflags);
742 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000743 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000744
bellard28be6232007-11-11 22:23:38 +0000745 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000746 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000747 magic = 0xffff;
748 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000749 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000750
bellard66fb9762003-03-23 01:06:05 +0000751 /* non-iBCS2 extensions.. */
752 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000753 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000754 return err;
755}
756
757/*
758 * Determine which stack to use..
759 */
760
bellard579a97f2007-11-11 14:26:47 +0000761static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000762get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000763{
764 unsigned long esp;
765
766 /* Default to using normal stack */
767 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000768 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000769 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000770 if (sas_ss_flags(esp) == 0)
771 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
772 }
bellard66fb9762003-03-23 01:06:05 +0000773
774 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000775 else
bellarda52c7572003-06-21 13:14:12 +0000776 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000777 !(ka->sa_flags & TARGET_SA_RESTORER) &&
778 ka->sa_restorer) {
779 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000780 }
bellard579a97f2007-11-11 14:26:47 +0000781 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000782}
783
bellard579a97f2007-11-11 14:26:47 +0000784/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000785static void setup_frame(int sig, struct target_sigaction *ka,
bellard66fb9762003-03-23 01:06:05 +0000786 target_sigset_t *set, CPUX86State *env)
787{
bellard579a97f2007-11-11 14:26:47 +0000788 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000789 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000790 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000791
bellard579a97f2007-11-11 14:26:47 +0000792 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000793
bellard579a97f2007-11-11 14:26:47 +0000794 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000795 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000796
thsc3b5bc82007-12-02 06:31:25 +0000797 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000798 &frame->sig);
799 if (err)
800 goto give_sigsegv;
801
bellard28be6232007-11-11 22:23:38 +0000802 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
803 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000804 if (err)
805 goto give_sigsegv;
806
bellard92319442004-06-19 16:58:13 +0000807 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
808 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
809 goto give_sigsegv;
810 }
bellard66fb9762003-03-23 01:06:05 +0000811
812 /* Set up to return from userspace. If provided, use a stub
813 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000814 if (ka->sa_flags & TARGET_SA_RESTORER) {
815 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000816 } else {
bellard775b58d2007-11-11 16:22:17 +0000817 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000818 abi_ulong retcode_addr;
819 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
820 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000821 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000822 val16 = 0xb858;
823 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000824 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000825 val16 = 0x80cd;
826 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000827 }
828
829 if (err)
830 goto give_sigsegv;
831
832 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000833 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000834 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000835
836 cpu_x86_load_seg(env, R_DS, __USER_DS);
837 cpu_x86_load_seg(env, R_ES, __USER_DS);
838 cpu_x86_load_seg(env, R_SS, __USER_DS);
839 cpu_x86_load_seg(env, R_CS, __USER_CS);
840 env->eflags &= ~TF_MASK;
841
bellard579a97f2007-11-11 14:26:47 +0000842 unlock_user_struct(frame, frame_addr, 1);
843
bellard66fb9762003-03-23 01:06:05 +0000844 return;
845
846give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000847 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000848 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000849 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000850 force_sig(TARGET_SIGSEGV /* , current */);
851}
852
bellard579a97f2007-11-11 14:26:47 +0000853/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000854static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard9de5e442003-03-23 16:49:39 +0000855 target_siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +0000856 target_sigset_t *set, CPUX86State *env)
857{
bellard28be6232007-11-11 22:23:38 +0000858 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000859 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000860 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000861
bellard579a97f2007-11-11 14:26:47 +0000862 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000863
bellard579a97f2007-11-11 14:26:47 +0000864 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000865 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000866
thsc3b5bc82007-12-02 06:31:25 +0000867 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000868 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000869 addr = frame_addr + offsetof(struct rt_sigframe, info);
870 err |= __put_user(addr, &frame->pinfo);
871 addr = frame_addr + offsetof(struct rt_sigframe, uc);
872 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000873 err |= copy_siginfo_to_user(&frame->info, info);
874 if (err)
875 goto give_sigsegv;
876
877 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000878 err |= __put_user(0, &frame->uc.tuc_flags);
879 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000880 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000881 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000882 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000883 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000884 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000885 &frame->uc.tuc_stack.ss_size);
886 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000887 env, set->sig[0],
888 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000889 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000890 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000891 goto give_sigsegv;
892 }
bellard66fb9762003-03-23 01:06:05 +0000893
894 /* Set up to return from userspace. If provided, use a stub
895 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000896 if (ka->sa_flags & TARGET_SA_RESTORER) {
897 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000898 } else {
bellard775b58d2007-11-11 16:22:17 +0000899 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000900 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
901 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000902 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000903 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000904 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000905 val16 = 0x80cd;
906 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000907 }
908
909 if (err)
910 goto give_sigsegv;
911
912 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000913 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000914 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000915
916 cpu_x86_load_seg(env, R_DS, __USER_DS);
917 cpu_x86_load_seg(env, R_ES, __USER_DS);
918 cpu_x86_load_seg(env, R_SS, __USER_DS);
919 cpu_x86_load_seg(env, R_CS, __USER_CS);
920 env->eflags &= ~TF_MASK;
921
bellard579a97f2007-11-11 14:26:47 +0000922 unlock_user_struct(frame, frame_addr, 1);
923
bellard66fb9762003-03-23 01:06:05 +0000924 return;
925
926give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000927 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000928 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000929 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000930 force_sig(TARGET_SIGSEGV /* , current */);
931}
932
933static int
934restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
935{
936 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000937 abi_ulong fpstate_addr;
938 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000939
bellard28be6232007-11-11 22:23:38 +0000940 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
941 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
942 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
943 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +0000944
bellard28be6232007-11-11 22:23:38 +0000945 env->regs[R_EDI] = tswapl(sc->edi);
946 env->regs[R_ESI] = tswapl(sc->esi);
947 env->regs[R_EBP] = tswapl(sc->ebp);
948 env->regs[R_ESP] = tswapl(sc->esp);
949 env->regs[R_EBX] = tswapl(sc->ebx);
950 env->regs[R_EDX] = tswapl(sc->edx);
951 env->regs[R_ECX] = tswapl(sc->ecx);
952 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +0000953
954 cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
955 cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +0000956
bellard28be6232007-11-11 22:23:38 +0000957 tmpflags = tswapl(sc->eflags);
958 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
959 // regs->orig_eax = -1; /* disable syscall checks */
960
961 fpstate_addr = tswapl(sc->fpstate);
962 if (fpstate_addr != 0) {
963 if (!access_ok(VERIFY_READ, fpstate_addr,
964 sizeof(struct target_fpstate)))
965 goto badframe;
966 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000967 }
968
bellard28be6232007-11-11 22:23:38 +0000969 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +0000970 return err;
bellard66fb9762003-03-23 01:06:05 +0000971badframe:
972 return 1;
bellard66fb9762003-03-23 01:06:05 +0000973}
974
975long do_sigreturn(CPUX86State *env)
976{
bellard579a97f2007-11-11 14:26:47 +0000977 struct sigframe *frame;
978 abi_ulong frame_addr = env->regs[R_ESP] - 8;
bellard66fb9762003-03-23 01:06:05 +0000979 target_sigset_t target_set;
980 sigset_t set;
981 int eax, i;
982
bellard447db212003-05-10 15:10:36 +0000983#if defined(DEBUG_SIGNAL)
984 fprintf(stderr, "do_sigreturn\n");
985#endif
bellard579a97f2007-11-11 14:26:47 +0000986 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
987 goto badframe;
bellard66fb9762003-03-23 01:06:05 +0000988 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +0000989 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
990 goto badframe;
991 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
992 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
993 goto badframe;
994 }
bellard66fb9762003-03-23 01:06:05 +0000995
bellard92319442004-06-19 16:58:13 +0000996 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +0000997 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +0000998
bellard66fb9762003-03-23 01:06:05 +0000999 /* restore registers */
1000 if (restore_sigcontext(env, &frame->sc, &eax))
1001 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001002 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001003 return eax;
1004
1005badframe:
bellard579a97f2007-11-11 14:26:47 +00001006 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001007 force_sig(TARGET_SIGSEGV);
1008 return 0;
1009}
1010
1011long do_rt_sigreturn(CPUX86State *env)
1012{
bellard28be6232007-11-11 22:23:38 +00001013 abi_ulong frame_addr;
1014 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001015 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001016 int eax;
1017
bellard28be6232007-11-11 22:23:38 +00001018 frame_addr = env->regs[R_ESP] - 4;
1019 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1020 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001021 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +00001022 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001023
bellardb8076a72005-04-07 22:20:31 +00001024 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001025 goto badframe;
1026
bellard28be6232007-11-11 22:23:38 +00001027 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1028 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001029 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001030
bellard28be6232007-11-11 22:23:38 +00001031 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001032 return eax;
1033
1034badframe:
bellard28be6232007-11-11 22:23:38 +00001035 unlock_user_struct(frame, frame_addr, 0);
1036 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001037 return 0;
1038}
1039
bellard43fff232003-07-09 19:31:39 +00001040#elif defined(TARGET_ARM)
1041
1042struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001043 abi_ulong trap_no;
1044 abi_ulong error_code;
1045 abi_ulong oldmask;
1046 abi_ulong arm_r0;
1047 abi_ulong arm_r1;
1048 abi_ulong arm_r2;
1049 abi_ulong arm_r3;
1050 abi_ulong arm_r4;
1051 abi_ulong arm_r5;
1052 abi_ulong arm_r6;
1053 abi_ulong arm_r7;
1054 abi_ulong arm_r8;
1055 abi_ulong arm_r9;
1056 abi_ulong arm_r10;
1057 abi_ulong arm_fp;
1058 abi_ulong arm_ip;
1059 abi_ulong arm_sp;
1060 abi_ulong arm_lr;
1061 abi_ulong arm_pc;
1062 abi_ulong arm_cpsr;
1063 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001064};
1065
pbrooka745ec62008-05-06 15:36:17 +00001066struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001067 abi_ulong tuc_flags;
1068 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +00001069 target_stack_t tuc_stack;
1070 struct target_sigcontext tuc_mcontext;
1071 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001072};
1073
pbrooka745ec62008-05-06 15:36:17 +00001074struct target_ucontext_v2 {
1075 abi_ulong tuc_flags;
1076 abi_ulong tuc_link;
1077 target_stack_t tuc_stack;
1078 struct target_sigcontext tuc_mcontext;
1079 target_sigset_t tuc_sigmask; /* mask last for extensibility */
1080 char __unused[128 - sizeof(sigset_t)];
1081 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1082};
1083
pbrooka8c33202008-05-07 23:22:46 +00001084struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001085{
1086 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001087 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1088 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001089};
1090
pbrooka8c33202008-05-07 23:22:46 +00001091struct sigframe_v2
1092{
1093 struct target_ucontext_v2 uc;
1094 abi_ulong retcode;
1095};
1096
pbrooka745ec62008-05-06 15:36:17 +00001097struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001098{
bellardf8b0aa22007-11-11 23:03:42 +00001099 abi_ulong pinfo;
1100 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001101 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001102 struct target_ucontext_v1 uc;
1103 abi_ulong retcode;
1104};
1105
1106struct rt_sigframe_v2
1107{
1108 struct target_siginfo info;
1109 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001110 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001111};
1112
1113#define TARGET_CONFIG_CPU_32 1
1114
1115/*
1116 * For ARM syscalls, we encode the syscall number into the instruction.
1117 */
1118#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1119#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1120
1121/*
1122 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1123 * need two 16-bit instructions.
1124 */
1125#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1126#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1127
blueswir1992f48a2007-10-14 16:27:31 +00001128static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001129 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1130 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1131};
1132
1133
bellard43fff232003-07-09 19:31:39 +00001134#define __get_user_error(x,p,e) __get_user(x, p)
1135
1136static inline int valid_user_regs(CPUState *regs)
1137{
1138 return 1;
1139}
1140
pbrooka8c33202008-05-07 23:22:46 +00001141static void
bellard43fff232003-07-09 19:31:39 +00001142setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
bellardf8b0aa22007-11-11 23:03:42 +00001143 CPUState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001144{
pbrooka8c33202008-05-07 23:22:46 +00001145 __put_user(env->regs[0], &sc->arm_r0);
1146 __put_user(env->regs[1], &sc->arm_r1);
1147 __put_user(env->regs[2], &sc->arm_r2);
1148 __put_user(env->regs[3], &sc->arm_r3);
1149 __put_user(env->regs[4], &sc->arm_r4);
1150 __put_user(env->regs[5], &sc->arm_r5);
1151 __put_user(env->regs[6], &sc->arm_r6);
1152 __put_user(env->regs[7], &sc->arm_r7);
1153 __put_user(env->regs[8], &sc->arm_r8);
1154 __put_user(env->regs[9], &sc->arm_r9);
1155 __put_user(env->regs[10], &sc->arm_r10);
1156 __put_user(env->regs[11], &sc->arm_fp);
1157 __put_user(env->regs[12], &sc->arm_ip);
1158 __put_user(env->regs[13], &sc->arm_sp);
1159 __put_user(env->regs[14], &sc->arm_lr);
1160 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001161#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001162 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001163#endif
1164
pbrooka8c33202008-05-07 23:22:46 +00001165 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1166 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1167 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1168 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001169}
1170
bellard579a97f2007-11-11 14:26:47 +00001171static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00001172get_sigframe(struct target_sigaction *ka, CPUState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001173{
1174 unsigned long sp = regs->regs[13];
1175
bellard43fff232003-07-09 19:31:39 +00001176 /*
1177 * This is the X/Open sanctioned signal stack switching.
1178 */
pbrook624f7972008-05-31 16:11:38 +00001179 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001180 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001181 /*
1182 * ATPCS B01 mandates 8-byte alignment
1183 */
bellard579a97f2007-11-11 14:26:47 +00001184 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001185}
1186
1187static int
pbrook624f7972008-05-31 16:11:38 +00001188setup_return(CPUState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001189 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001190{
pbrook624f7972008-05-31 16:11:38 +00001191 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001192 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001193 int thumb = handler & 1;
bellard43fff232003-07-09 19:31:39 +00001194
pbrook624f7972008-05-31 16:11:38 +00001195 if (ka->sa_flags & TARGET_SA_RESTORER) {
1196 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001197 } else {
1198 unsigned int idx = thumb;
1199
pbrook624f7972008-05-31 16:11:38 +00001200 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001201 idx += 2;
1202
1203 if (__put_user(retcodes[idx], rc))
1204 return 1;
1205#if 0
blueswir1992f48a2007-10-14 16:27:31 +00001206 flush_icache_range((abi_ulong)rc,
1207 (abi_ulong)(rc + 1));
bellard43fff232003-07-09 19:31:39 +00001208#endif
bellardf8b0aa22007-11-11 23:03:42 +00001209 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001210 }
1211
1212 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001213 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001214 env->regs[14] = retcode;
1215 env->regs[15] = handler & (thumb ? ~1 : ~3);
pbrook75b680e2008-03-21 16:07:30 +00001216 env->thumb = thumb;
bellard43fff232003-07-09 19:31:39 +00001217
bellardb5ff1b32005-11-26 10:38:39 +00001218#if 0
bellard43fff232003-07-09 19:31:39 +00001219#ifdef TARGET_CONFIG_CPU_32
1220 env->cpsr = cpsr;
1221#endif
bellardb5ff1b32005-11-26 10:38:39 +00001222#endif
bellard43fff232003-07-09 19:31:39 +00001223
1224 return 0;
1225}
1226
pbrooka8c33202008-05-07 23:22:46 +00001227static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
1228 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001229{
pbrooka8c33202008-05-07 23:22:46 +00001230 struct target_sigaltstack stack;
1231 int i;
1232
1233 /* Clear all the bits of the ucontext we don't use. */
1234 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1235
1236 memset(&stack, 0, sizeof(stack));
1237 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1238 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1239 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1240 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1241
1242 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
1243 /* FIXME: Save coprocessor signal frame. */
1244 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1245 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1246 }
1247}
1248
1249/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001250static void setup_frame_v1(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001251 target_sigset_t *set, CPUState *regs)
1252{
1253 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001254 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001255 int i;
bellard43fff232003-07-09 19:31:39 +00001256
bellard579a97f2007-11-11 14:26:47 +00001257 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1258 return;
1259
pbrooka8c33202008-05-07 23:22:46 +00001260 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001261
bellard92319442004-06-19 16:58:13 +00001262 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1263 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001264 goto end;
bellard43fff232003-07-09 19:31:39 +00001265 }
1266
pbrooka8c33202008-05-07 23:22:46 +00001267 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1268 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001269
1270end:
1271 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001272}
1273
pbrook624f7972008-05-31 16:11:38 +00001274static void setup_frame_v2(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001275 target_sigset_t *set, CPUState *regs)
1276{
1277 struct sigframe_v2 *frame;
1278 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1279
1280 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1281 return;
1282
1283 setup_sigframe_v2(&frame->uc, set, regs);
1284
1285 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1286 frame_addr + offsetof(struct sigframe_v2, retcode));
1287
1288 unlock_user_struct(frame, frame_addr, 1);
1289}
1290
pbrook624f7972008-05-31 16:11:38 +00001291static void setup_frame(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001292 target_sigset_t *set, CPUState *regs)
1293{
1294 if (get_osversion() >= 0x020612) {
1295 setup_frame_v2(usig, ka, set, regs);
1296 } else {
1297 setup_frame_v1(usig, ka, set, regs);
1298 }
bellard43fff232003-07-09 19:31:39 +00001299}
1300
bellard579a97f2007-11-11 14:26:47 +00001301/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001302static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001303 target_siginfo_t *info,
1304 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001305{
pbrooka745ec62008-05-06 15:36:17 +00001306 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001307 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001308 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001309 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001310 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001311
bellard579a97f2007-11-11 14:26:47 +00001312 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001313 return /* 1 */;
1314
pbrooka745ec62008-05-06 15:36:17 +00001315 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001316 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001317 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001318 __put_user(uc_addr, &frame->puc);
1319 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001320
1321 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001322 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001323
thsa04e1342007-09-27 13:57:58 +00001324 memset(&stack, 0, sizeof(stack));
1325 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1326 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1327 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001328 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001329
pbrooka8c33202008-05-07 23:22:46 +00001330 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001331 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001332 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001333 goto end;
bellard92319442004-06-19 16:58:13 +00001334 }
bellard43fff232003-07-09 19:31:39 +00001335
pbrooka8c33202008-05-07 23:22:46 +00001336 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1337 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001338
pbrooka8c33202008-05-07 23:22:46 +00001339 env->regs[1] = info_addr;
1340 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001341
1342end:
1343 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001344}
1345
pbrook624f7972008-05-31 16:11:38 +00001346static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001347 target_siginfo_t *info,
1348 target_sigset_t *set, CPUState *env)
1349{
1350 struct rt_sigframe_v2 *frame;
1351 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001352 abi_ulong info_addr, uc_addr;
1353
1354 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1355 return /* 1 */;
1356
1357 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1358 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001359 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001360
pbrooka8c33202008-05-07 23:22:46 +00001361 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001362
pbrooka8c33202008-05-07 23:22:46 +00001363 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1364 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001365
pbrooka8c33202008-05-07 23:22:46 +00001366 env->regs[1] = info_addr;
1367 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001368
bellard579a97f2007-11-11 14:26:47 +00001369 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001370}
1371
pbrook624f7972008-05-31 16:11:38 +00001372static void setup_rt_frame(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001373 target_siginfo_t *info,
1374 target_sigset_t *set, CPUState *env)
1375{
1376 if (get_osversion() >= 0x020612) {
1377 setup_rt_frame_v2(usig, ka, info, set, env);
1378 } else {
1379 setup_rt_frame_v1(usig, ka, info, set, env);
1380 }
1381}
1382
bellard43fff232003-07-09 19:31:39 +00001383static int
1384restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
1385{
1386 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001387 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001388
1389 __get_user_error(env->regs[0], &sc->arm_r0, err);
1390 __get_user_error(env->regs[1], &sc->arm_r1, err);
1391 __get_user_error(env->regs[2], &sc->arm_r2, err);
1392 __get_user_error(env->regs[3], &sc->arm_r3, err);
1393 __get_user_error(env->regs[4], &sc->arm_r4, err);
1394 __get_user_error(env->regs[5], &sc->arm_r5, err);
1395 __get_user_error(env->regs[6], &sc->arm_r6, err);
1396 __get_user_error(env->regs[7], &sc->arm_r7, err);
1397 __get_user_error(env->regs[8], &sc->arm_r8, err);
1398 __get_user_error(env->regs[9], &sc->arm_r9, err);
1399 __get_user_error(env->regs[10], &sc->arm_r10, err);
1400 __get_user_error(env->regs[11], &sc->arm_fp, err);
1401 __get_user_error(env->regs[12], &sc->arm_ip, err);
1402 __get_user_error(env->regs[13], &sc->arm_sp, err);
1403 __get_user_error(env->regs[14], &sc->arm_lr, err);
1404 __get_user_error(env->regs[15], &sc->arm_pc, err);
1405#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001406 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001407 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001408#endif
1409
1410 err |= !valid_user_regs(env);
1411
1412 return err;
1413}
1414
aurel32dc7eea62009-01-30 20:15:32 +00001415static long do_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001416{
bellardf8b0aa22007-11-11 23:03:42 +00001417 abi_ulong frame_addr;
pbrooka8c33202008-05-07 23:22:46 +00001418 struct sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001419 target_sigset_t set;
1420 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001421 int i;
bellard43fff232003-07-09 19:31:39 +00001422
1423 /*
1424 * Since we stacked the signal on a 64-bit boundary,
1425 * then 'sp' should be word aligned here. If it's
1426 * not, then the user is trying to mess with us.
1427 */
1428 if (env->regs[13] & 7)
1429 goto badframe;
1430
bellardf8b0aa22007-11-11 23:03:42 +00001431 frame_addr = env->regs[13];
1432 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1433 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001434
bellard92319442004-06-19 16:58:13 +00001435 if (__get_user(set.sig[0], &frame->sc.oldmask))
1436 goto badframe;
1437 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1438 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1439 goto badframe;
1440 }
bellard43fff232003-07-09 19:31:39 +00001441
bellard92319442004-06-19 16:58:13 +00001442 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001443 sigprocmask(SIG_SETMASK, &host_set, NULL);
1444
1445 if (restore_sigcontext(env, &frame->sc))
1446 goto badframe;
1447
1448#if 0
1449 /* Send SIGTRAP if we're single-stepping */
1450 if (ptrace_cancel_bpt(current))
1451 send_sig(SIGTRAP, current, 1);
1452#endif
bellardf8b0aa22007-11-11 23:03:42 +00001453 unlock_user_struct(frame, frame_addr, 0);
1454 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001455
1456badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001457 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001458 force_sig(SIGSEGV /* , current */);
1459 return 0;
1460}
1461
pbrooka8c33202008-05-07 23:22:46 +00001462static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr,
1463 struct target_ucontext_v2 *uc)
1464{
1465 sigset_t host_set;
1466
1467 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1468 sigprocmask(SIG_SETMASK, &host_set, NULL);
1469
1470 if (restore_sigcontext(env, &uc->tuc_mcontext))
1471 return 1;
1472
1473 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1474 return 1;
1475
1476#if 0
1477 /* Send SIGTRAP if we're single-stepping */
1478 if (ptrace_cancel_bpt(current))
1479 send_sig(SIGTRAP, current, 1);
1480#endif
1481
1482 return 0;
1483}
1484
aurel32dc7eea62009-01-30 20:15:32 +00001485static long do_sigreturn_v2(CPUState *env)
pbrooka8c33202008-05-07 23:22:46 +00001486{
1487 abi_ulong frame_addr;
1488 struct sigframe_v2 *frame;
1489
1490 /*
1491 * Since we stacked the signal on a 64-bit boundary,
1492 * then 'sp' should be word aligned here. If it's
1493 * not, then the user is trying to mess with us.
1494 */
1495 if (env->regs[13] & 7)
1496 goto badframe;
1497
1498 frame_addr = env->regs[13];
1499 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1500 goto badframe;
1501
1502 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1503 goto badframe;
1504
1505 unlock_user_struct(frame, frame_addr, 0);
1506 return env->regs[0];
1507
1508badframe:
1509 unlock_user_struct(frame, frame_addr, 0);
1510 force_sig(SIGSEGV /* , current */);
1511 return 0;
1512}
1513
1514long do_sigreturn(CPUState *env)
1515{
1516 if (get_osversion() >= 0x020612) {
1517 return do_sigreturn_v2(env);
1518 } else {
1519 return do_sigreturn_v1(env);
1520 }
1521}
1522
aurel32dc7eea62009-01-30 20:15:32 +00001523static long do_rt_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001524{
bellardf8b0aa22007-11-11 23:03:42 +00001525 abi_ulong frame_addr;
pbrooka745ec62008-05-06 15:36:17 +00001526 struct rt_sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001527 sigset_t host_set;
1528
1529 /*
1530 * Since we stacked the signal on a 64-bit boundary,
1531 * then 'sp' should be word aligned here. If it's
1532 * not, then the user is trying to mess with us.
1533 */
1534 if (env->regs[13] & 7)
1535 goto badframe;
1536
bellardf8b0aa22007-11-11 23:03:42 +00001537 frame_addr = env->regs[13];
1538 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1539 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001540
bellardb8076a72005-04-07 22:20:31 +00001541 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00001542 sigprocmask(SIG_SETMASK, &host_set, NULL);
1543
bellardb8076a72005-04-07 22:20:31 +00001544 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00001545 goto badframe;
1546
pbrooka745ec62008-05-06 15:36:17 +00001547 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 +00001548 goto badframe;
1549
bellard43fff232003-07-09 19:31:39 +00001550#if 0
1551 /* Send SIGTRAP if we're single-stepping */
1552 if (ptrace_cancel_bpt(current))
1553 send_sig(SIGTRAP, current, 1);
1554#endif
bellardf8b0aa22007-11-11 23:03:42 +00001555 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001556 return env->regs[0];
1557
1558badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001559 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001560 force_sig(SIGSEGV /* , current */);
1561 return 0;
1562}
1563
aurel32dc7eea62009-01-30 20:15:32 +00001564static long do_rt_sigreturn_v2(CPUState *env)
pbrooka745ec62008-05-06 15:36:17 +00001565{
1566 abi_ulong frame_addr;
1567 struct rt_sigframe_v2 *frame;
pbrooka745ec62008-05-06 15:36:17 +00001568
1569 /*
1570 * Since we stacked the signal on a 64-bit boundary,
1571 * then 'sp' should be word aligned here. If it's
1572 * not, then the user is trying to mess with us.
1573 */
1574 if (env->regs[13] & 7)
1575 goto badframe;
1576
1577 frame_addr = env->regs[13];
1578 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1579 goto badframe;
1580
pbrooka8c33202008-05-07 23:22:46 +00001581 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1582 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00001583
pbrooka745ec62008-05-06 15:36:17 +00001584 unlock_user_struct(frame, frame_addr, 0);
1585 return env->regs[0];
1586
1587badframe:
1588 unlock_user_struct(frame, frame_addr, 0);
1589 force_sig(SIGSEGV /* , current */);
1590 return 0;
1591}
1592
1593long do_rt_sigreturn(CPUState *env)
1594{
1595 if (get_osversion() >= 0x020612) {
1596 return do_rt_sigreturn_v2(env);
1597 } else {
1598 return do_rt_sigreturn_v1(env);
1599 }
1600}
1601
bellard6d5e2162004-09-30 22:04:13 +00001602#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00001603
bellard6d5e2162004-09-30 22:04:13 +00001604#define __SUNOS_MAXWIN 31
1605
1606/* This is what SunOS does, so shall I. */
1607struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001608 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00001609
blueswir1992f48a2007-10-14 16:27:31 +00001610 abi_ulong sigc_mask; /* sigmask to restore */
1611 abi_ulong sigc_sp; /* stack pointer */
1612 abi_ulong sigc_pc; /* program counter */
1613 abi_ulong sigc_npc; /* next program counter */
1614 abi_ulong sigc_psr; /* for condition codes etc */
1615 abi_ulong sigc_g1; /* User uses these two registers */
1616 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00001617
1618 /* Now comes information regarding the users window set
1619 * at the time of the signal.
1620 */
blueswir1992f48a2007-10-14 16:27:31 +00001621 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00001622
1623 /* stack ptrs for each regwin buf */
1624 char *sigc_spbuf[__SUNOS_MAXWIN];
1625
1626 /* Windows to restore after signal */
1627 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001628 abi_ulong locals[8];
1629 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00001630 } sigc_wbuf[__SUNOS_MAXWIN];
1631};
1632/* A Sparc stack frame */
1633struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00001634 abi_ulong locals[8];
1635 abi_ulong ins[6];
bellard6d5e2162004-09-30 22:04:13 +00001636 struct sparc_stackf *fp;
blueswir1992f48a2007-10-14 16:27:31 +00001637 abi_ulong callers_pc;
bellard6d5e2162004-09-30 22:04:13 +00001638 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00001639 abi_ulong xargs[6];
1640 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00001641};
1642
1643typedef struct {
1644 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001645 abi_ulong psr;
1646 abi_ulong pc;
1647 abi_ulong npc;
1648 abi_ulong y;
1649 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00001650 } si_regs;
1651 int si_mask;
1652} __siginfo_t;
1653
1654typedef struct {
1655 unsigned long si_float_regs [32];
1656 unsigned long si_fsr;
1657 unsigned long si_fpqdepth;
1658 struct {
1659 unsigned long *insn_addr;
1660 unsigned long insn;
1661 } si_fpqueue [16];
bellard74ccb342006-07-18 21:23:34 +00001662} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00001663
1664
1665struct target_signal_frame {
1666 struct sparc_stackf ss;
1667 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00001668 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00001669 abi_ulong insns[2] __attribute__ ((aligned (8)));
1670 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
1671 abi_ulong extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001672 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001673};
1674struct target_rt_signal_frame {
1675 struct sparc_stackf ss;
1676 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00001677 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00001678 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00001679 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00001680 unsigned int insns[2];
1681 stack_t stack;
1682 unsigned int extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001683 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001684};
1685
bellarde80cfcf2004-12-19 23:18:01 +00001686#define UREG_O0 16
1687#define UREG_O6 22
1688#define UREG_I0 0
1689#define UREG_I1 1
1690#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00001691#define UREG_I3 3
1692#define UREG_I4 4
1693#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00001694#define UREG_I6 6
1695#define UREG_I7 7
1696#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00001697#define UREG_FP UREG_I6
1698#define UREG_SP UREG_O6
1699
pbrook624f7972008-05-31 16:11:38 +00001700static inline abi_ulong get_sigframe(struct target_sigaction *sa,
bellard459a4012007-11-11 19:45:10 +00001701 CPUState *env, unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00001702{
bellard459a4012007-11-11 19:45:10 +00001703 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00001704
1705 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00001706
1707 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00001708 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00001709 if (!on_sig_stack(sp)
1710 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
1711 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00001712 }
bellard459a4012007-11-11 19:45:10 +00001713 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00001714}
1715
1716static int
blueswir1992f48a2007-10-14 16:27:31 +00001717setup___siginfo(__siginfo_t *si, CPUState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00001718{
1719 int err = 0, i;
1720
bellard6d5e2162004-09-30 22:04:13 +00001721 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00001722 err |= __put_user(env->pc, &si->si_regs.pc);
1723 err |= __put_user(env->npc, &si->si_regs.npc);
1724 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001725 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00001726 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
1727 }
bellarda315a142005-01-30 22:59:18 +00001728 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001729 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00001730 }
bellard6d5e2162004-09-30 22:04:13 +00001731 err |= __put_user(mask, &si->si_mask);
1732 return err;
1733}
bellarde80cfcf2004-12-19 23:18:01 +00001734
bellard80a9d032005-01-03 23:31:27 +00001735#if 0
bellard6d5e2162004-09-30 22:04:13 +00001736static int
1737setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
1738 CPUState *env, unsigned long mask)
1739{
1740 int err = 0;
1741
1742 err |= __put_user(mask, &sc->sigc_mask);
1743 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
1744 err |= __put_user(env->pc, &sc->sigc_pc);
1745 err |= __put_user(env->npc, &sc->sigc_npc);
1746 err |= __put_user(env->psr, &sc->sigc_psr);
1747 err |= __put_user(env->gregs[1], &sc->sigc_g1);
1748 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
1749
1750 return err;
1751}
bellard80a9d032005-01-03 23:31:27 +00001752#endif
bellard6d5e2162004-09-30 22:04:13 +00001753#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
1754
pbrook624f7972008-05-31 16:11:38 +00001755static void setup_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001756 target_sigset_t *set, CPUState *env)
1757{
bellard459a4012007-11-11 19:45:10 +00001758 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001759 struct target_signal_frame *sf;
1760 int sigframe_size, err, i;
1761
1762 /* 1. Make sure everything is clean */
1763 //synchronize_user_stack();
1764
1765 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00001766 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00001767
bellard459a4012007-11-11 19:45:10 +00001768 sf = lock_user(VERIFY_WRITE, sf_addr,
1769 sizeof(struct target_signal_frame), 0);
1770 if (!sf)
1771 goto sigsegv;
1772
bellarde80cfcf2004-12-19 23:18:01 +00001773 //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 +00001774#if 0
1775 if (invalid_frame_pointer(sf, sigframe_size))
1776 goto sigill_and_return;
1777#endif
1778 /* 2. Save the current process state */
1779 err = setup___siginfo(&sf->info, env, set->sig[0]);
1780 err |= __put_user(0, &sf->extra_size);
1781
1782 //err |= save_fpu_state(regs, &sf->fpu_state);
1783 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
1784
1785 err |= __put_user(set->sig[0], &sf->info.si_mask);
1786 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
1787 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
1788 }
1789
bellarda315a142005-01-30 22:59:18 +00001790 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001791 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00001792 }
bellarda315a142005-01-30 22:59:18 +00001793 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001794 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00001795 }
bellard6d5e2162004-09-30 22:04:13 +00001796 if (err)
1797 goto sigsegv;
1798
1799 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00001800 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001801 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00001802 env->regwptr[UREG_I1] = sf_addr +
1803 offsetof(struct target_signal_frame, info);
1804 env->regwptr[UREG_I2] = sf_addr +
1805 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00001806
1807 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00001808 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00001809 env->npc = (env->pc + 4);
1810 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00001811 if (ka->sa_restorer)
1812 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00001813 else {
bellard775b58d2007-11-11 16:22:17 +00001814 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00001815
1816 env->regwptr[UREG_I7] = sf_addr +
1817 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00001818
1819 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00001820 val32 = 0x821020d8;
1821 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00001822
1823 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00001824 val32 = 0x91d02010;
1825 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00001826 if (err)
1827 goto sigsegv;
1828
1829 /* Flush instruction space. */
1830 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00001831 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00001832 }
bellard459a4012007-11-11 19:45:10 +00001833 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001834 return;
bellard459a4012007-11-11 19:45:10 +00001835#if 0
1836sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00001837 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00001838#endif
bellard6d5e2162004-09-30 22:04:13 +00001839sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00001840 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00001841 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001842 force_sig(TARGET_SIGSEGV);
1843}
1844static inline int
bellard74ccb342006-07-18 21:23:34 +00001845restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00001846{
1847 int err;
1848#if 0
1849#ifdef CONFIG_SMP
1850 if (current->flags & PF_USEDFPU)
1851 regs->psr &= ~PSR_EF;
1852#else
1853 if (current == last_task_used_math) {
1854 last_task_used_math = 0;
1855 regs->psr &= ~PSR_EF;
1856 }
1857#endif
1858 current->used_math = 1;
1859 current->flags &= ~PF_USEDFPU;
1860#endif
1861#if 0
1862 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
1863 return -EFAULT;
1864#endif
1865
bellardfafffae2006-10-28 12:09:16 +00001866#if 0
1867 /* XXX: incorrect */
bellard6d5e2162004-09-30 22:04:13 +00001868 err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
1869 (sizeof(unsigned long) * 32));
bellardfafffae2006-10-28 12:09:16 +00001870#endif
bellard6d5e2162004-09-30 22:04:13 +00001871 err |= __get_user(env->fsr, &fpu->si_fsr);
1872#if 0
1873 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
1874 if (current->thread.fpqdepth != 0)
1875 err |= __copy_from_user(&current->thread.fpqueue[0],
1876 &fpu->si_fpqueue[0],
1877 ((sizeof(unsigned long) +
1878 (sizeof(unsigned long *)))*16));
1879#endif
1880 return err;
1881}
1882
1883
pbrook624f7972008-05-31 16:11:38 +00001884static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001885 target_siginfo_t *info,
1886 target_sigset_t *set, CPUState *env)
1887{
1888 fprintf(stderr, "setup_rt_frame: not implemented\n");
1889}
1890
1891long do_sigreturn(CPUState *env)
1892{
bellardf8b0aa22007-11-11 23:03:42 +00001893 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001894 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00001895 uint32_t up_psr, pc, npc;
bellard6d5e2162004-09-30 22:04:13 +00001896 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00001897 sigset_t host_set;
bellardf8b0aa22007-11-11 23:03:42 +00001898 abi_ulong fpu_save_addr;
bellarde80cfcf2004-12-19 23:18:01 +00001899 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00001900
bellardf8b0aa22007-11-11 23:03:42 +00001901 sf_addr = env->regwptr[UREG_FP];
1902 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
1903 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00001904#if 0
bellarde80cfcf2004-12-19 23:18:01 +00001905 fprintf(stderr, "sigreturn\n");
1906 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 +00001907#endif
bellarde80cfcf2004-12-19 23:18:01 +00001908 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00001909
1910 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00001911
bellardf8b0aa22007-11-11 23:03:42 +00001912 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00001913 goto segv_and_exit;
1914
1915 err = __get_user(pc, &sf->info.si_regs.pc);
1916 err |= __get_user(npc, &sf->info.si_regs.npc);
1917
bellard6d5e2162004-09-30 22:04:13 +00001918 if ((pc | npc) & 3)
1919 goto segv_and_exit;
1920
1921 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00001922 err |= __get_user(up_psr, &sf->info.si_regs.psr);
1923
bellard6d5e2162004-09-30 22:04:13 +00001924 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00001925 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
1926 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
1927
1928 env->pc = pc;
1929 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00001930 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001931 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001932 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
1933 }
bellarda315a142005-01-30 22:59:18 +00001934 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001935 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
1936 }
bellard6d5e2162004-09-30 22:04:13 +00001937
bellardf8b0aa22007-11-11 23:03:42 +00001938 err |= __get_user(fpu_save_addr, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001939
bellarde80cfcf2004-12-19 23:18:01 +00001940 //if (fpu_save)
1941 // err |= restore_fpu_state(env, fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001942
1943 /* This is pretty much atomic, no amount locking would prevent
1944 * the races which exist anyways.
1945 */
1946 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00001947 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1948 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
1949 }
1950
1951 target_to_host_sigset_internal(&host_set, &set);
1952 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00001953
1954 if (err)
1955 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00001956 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001957 return env->regwptr[0];
1958
1959segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00001960 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001961 force_sig(TARGET_SIGSEGV);
1962}
1963
1964long do_rt_sigreturn(CPUState *env)
1965{
1966 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00001967 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00001968}
1969
bellard459a4012007-11-11 19:45:10 +00001970#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00001971#define MC_TSTATE 0
1972#define MC_PC 1
1973#define MC_NPC 2
1974#define MC_Y 3
1975#define MC_G1 4
1976#define MC_G2 5
1977#define MC_G3 6
1978#define MC_G4 7
1979#define MC_G5 8
1980#define MC_G6 9
1981#define MC_G7 10
1982#define MC_O0 11
1983#define MC_O1 12
1984#define MC_O2 13
1985#define MC_O3 14
1986#define MC_O4 15
1987#define MC_O5 16
1988#define MC_O6 17
1989#define MC_O7 18
1990#define MC_NGREG 19
1991
blueswir1992f48a2007-10-14 16:27:31 +00001992typedef abi_ulong target_mc_greg_t;
blueswir15bfb56b2007-10-05 17:01:51 +00001993typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
1994
1995struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00001996 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00001997 uint32_t mcfq_insn;
1998};
1999
2000struct target_mc_fpu {
2001 union {
2002 uint32_t sregs[32];
2003 uint64_t dregs[32];
2004 //uint128_t qregs[16];
2005 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002006 abi_ulong mcfpu_fsr;
2007 abi_ulong mcfpu_fprs;
2008 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002009 struct target_mc_fq *mcfpu_fq;
2010 unsigned char mcfpu_qcnt;
2011 unsigned char mcfpu_qentsz;
2012 unsigned char mcfpu_enab;
2013};
2014typedef struct target_mc_fpu target_mc_fpu_t;
2015
2016typedef struct {
2017 target_mc_gregset_t mc_gregs;
2018 target_mc_greg_t mc_fp;
2019 target_mc_greg_t mc_i7;
2020 target_mc_fpu_t mc_fpregs;
2021} target_mcontext_t;
2022
2023struct target_ucontext {
2024 struct target_ucontext *uc_link;
blueswir1992f48a2007-10-14 16:27:31 +00002025 abi_ulong uc_flags;
blueswir15bfb56b2007-10-05 17:01:51 +00002026 target_sigset_t uc_sigmask;
2027 target_mcontext_t uc_mcontext;
2028};
2029
2030/* A V9 register window */
2031struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002032 abi_ulong locals[8];
2033 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002034};
2035
2036#define TARGET_STACK_BIAS 2047
2037
2038/* {set, get}context() needed for 64-bit SparcLinux userland. */
2039void sparc64_set_context(CPUSPARCState *env)
2040{
bellard459a4012007-11-11 19:45:10 +00002041 abi_ulong ucp_addr;
2042 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00002043 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002044 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002045 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002046 unsigned char fenab;
2047 int err;
2048 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002049
bellard459a4012007-11-11 19:45:10 +00002050 ucp_addr = env->regwptr[UREG_I0];
2051 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2052 goto do_sigsegv;
blueswir15bfb56b2007-10-05 17:01:51 +00002053 grp = &ucp->uc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002054 err = __get_user(pc, &((*grp)[MC_PC]));
2055 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002056 if (err || ((pc | npc) & 3))
2057 goto do_sigsegv;
2058 if (env->regwptr[UREG_I1]) {
2059 target_sigset_t target_set;
2060 sigset_t set;
2061
2062 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002063 if (__get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002064 goto do_sigsegv;
2065 } else {
bellard459a4012007-11-11 19:45:10 +00002066 abi_ulong *src, *dst;
2067 src = ucp->uc_sigmask.sig;
2068 dst = target_set.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002069 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002070 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002071 err |= __get_user(*dst, src);
blueswir15bfb56b2007-10-05 17:01:51 +00002072 if (err)
2073 goto do_sigsegv;
2074 }
2075 target_to_host_sigset_internal(&set, &target_set);
2076 sigprocmask(SIG_SETMASK, &set, NULL);
2077 }
2078 env->pc = pc;
2079 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002080 err |= __get_user(env->y, &((*grp)[MC_Y]));
2081 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002082 env->asi = (tstate >> 24) & 0xff;
2083 PUT_CCR(env, tstate >> 32);
2084 PUT_CWP64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002085 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2086 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2087 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2088 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2089 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2090 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2091 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2092 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2093 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2094 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2095 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2096 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2097 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2098 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2099 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002100
bellard579a97f2007-11-11 14:26:47 +00002101 err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp));
2102 err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002103
bellard459a4012007-11-11 19:45:10 +00002104 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2105 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2106 abi_ulong) != 0)
2107 goto do_sigsegv;
2108 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2109 abi_ulong) != 0)
2110 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002111 err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
2112 err |= __get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002113 {
2114 uint32_t *src, *dst;
2115 src = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2116 dst = env->fpr;
2117 /* XXX: check that the CPU storage is the same as user context */
2118 for (i = 0; i < 64; i++, dst++, src++)
2119 err |= __get_user(*dst, src);
2120 }
bellard579a97f2007-11-11 14:26:47 +00002121 err |= __get_user(env->fsr,
2122 &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
2123 err |= __get_user(env->gsr,
2124 &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002125 if (err)
2126 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002127 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002128 return;
2129 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002130 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002131 force_sig(SIGSEGV);
2132}
2133
2134void sparc64_get_context(CPUSPARCState *env)
2135{
bellard459a4012007-11-11 19:45:10 +00002136 abi_ulong ucp_addr;
2137 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00002138 target_mc_gregset_t *grp;
2139 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002140 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002141 int err;
2142 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002143 target_sigset_t target_set;
2144 sigset_t set;
2145
bellard459a4012007-11-11 19:45:10 +00002146 ucp_addr = env->regwptr[UREG_I0];
2147 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2148 goto do_sigsegv;
2149
blueswir15bfb56b2007-10-05 17:01:51 +00002150 mcp = &ucp->uc_mcontext;
2151 grp = &mcp->mc_gregs;
2152
2153 /* Skip over the trap instruction, first. */
2154 env->pc = env->npc;
2155 env->npc += 4;
2156
2157 err = 0;
2158
2159 sigprocmask(0, NULL, &set);
2160 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002161 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002162 err |= __put_user(target_set.sig[0],
2163 (abi_ulong *)&ucp->uc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002164 } else {
2165 abi_ulong *src, *dst;
2166 src = target_set.sig;
2167 dst = ucp->uc_sigmask.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002168 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002169 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002170 err |= __put_user(*src, dst);
blueswir15bfb56b2007-10-05 17:01:51 +00002171 if (err)
2172 goto do_sigsegv;
2173 }
2174
bellard459a4012007-11-11 19:45:10 +00002175 /* XXX: tstate must be saved properly */
2176 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002177 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2178 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2179 err |= __put_user(env->y, &((*grp)[MC_Y]));
2180 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2181 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2182 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2183 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2184 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2185 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2186 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2187 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2188 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2189 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2190 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2191 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2192 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2193 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2194 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002195
bellard459a4012007-11-11 19:45:10 +00002196 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2197 fp = i7 = 0;
2198 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2199 abi_ulong) != 0)
2200 goto do_sigsegv;
2201 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2202 abi_ulong) != 0)
2203 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002204 err |= __put_user(fp, &(mcp->mc_fp));
2205 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002206
bellard459a4012007-11-11 19:45:10 +00002207 {
2208 uint32_t *src, *dst;
2209 src = env->fpr;
2210 dst = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2211 /* XXX: check that the CPU storage is the same as user context */
2212 for (i = 0; i < 64; i++, dst++, src++)
2213 err |= __put_user(*src, dst);
2214 }
bellard579a97f2007-11-11 14:26:47 +00002215 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2216 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2217 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002218
2219 if (err)
2220 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002221 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002222 return;
2223 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002224 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002225 force_sig(SIGSEGV);
2226}
2227#endif
thsd26bc212007-11-08 18:05:37 +00002228#elif defined(TARGET_ABI_MIPSN64)
ths540635b2007-09-30 01:58:33 +00002229
2230# warning signal handling not implemented
2231
pbrook624f7972008-05-31 16:11:38 +00002232static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002233 target_sigset_t *set, CPUState *env)
2234{
2235 fprintf(stderr, "setup_frame: not implemented\n");
2236}
2237
pbrook624f7972008-05-31 16:11:38 +00002238static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002239 target_siginfo_t *info,
2240 target_sigset_t *set, CPUState *env)
2241{
2242 fprintf(stderr, "setup_rt_frame: not implemented\n");
2243}
2244
2245long do_sigreturn(CPUState *env)
2246{
2247 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002248 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002249}
2250
2251long do_rt_sigreturn(CPUState *env)
2252{
2253 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002254 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002255}
2256
thsd26bc212007-11-08 18:05:37 +00002257#elif defined(TARGET_ABI_MIPSN32)
ths540635b2007-09-30 01:58:33 +00002258
2259# warning signal handling not implemented
2260
pbrook624f7972008-05-31 16:11:38 +00002261static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002262 target_sigset_t *set, CPUState *env)
2263{
2264 fprintf(stderr, "setup_frame: not implemented\n");
2265}
2266
pbrook624f7972008-05-31 16:11:38 +00002267static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002268 target_siginfo_t *info,
2269 target_sigset_t *set, CPUState *env)
2270{
2271 fprintf(stderr, "setup_rt_frame: not implemented\n");
2272}
2273
2274long do_sigreturn(CPUState *env)
2275{
2276 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002277 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002278}
2279
2280long do_rt_sigreturn(CPUState *env)
2281{
2282 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002283 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002284}
2285
thsd26bc212007-11-08 18:05:37 +00002286#elif defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002287
2288struct target_sigcontext {
2289 uint32_t sc_regmask; /* Unused */
2290 uint32_t sc_status;
2291 uint64_t sc_pc;
2292 uint64_t sc_regs[32];
2293 uint64_t sc_fpregs[32];
2294 uint32_t sc_ownedfp; /* Unused */
2295 uint32_t sc_fpc_csr;
2296 uint32_t sc_fpc_eir; /* Unused */
2297 uint32_t sc_used_math;
2298 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
2299 uint64_t sc_mdhi;
2300 uint64_t sc_mdlo;
2301 target_ulong sc_hi1; /* Was sc_cause */
2302 target_ulong sc_lo1; /* Was sc_badvaddr */
2303 target_ulong sc_hi2; /* Was sc_sigset[4] */
2304 target_ulong sc_lo2;
2305 target_ulong sc_hi3;
2306 target_ulong sc_lo3;
2307};
2308
2309struct sigframe {
2310 uint32_t sf_ass[4]; /* argument save space for o32 */
2311 uint32_t sf_code[2]; /* signal trampoline */
2312 struct target_sigcontext sf_sc;
2313 target_sigset_t sf_mask;
2314};
2315
2316/* Install trampoline to jump back from signal handler */
2317static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2318{
2319 int err;
2320
2321 /*
2322 * Set up the return code ...
2323 *
2324 * li v0, __NR__foo_sigreturn
2325 * syscall
2326 */
2327
2328 err = __put_user(0x24020000 + syscall, tramp + 0);
2329 err |= __put_user(0x0000000c , tramp + 1);
2330 /* flush_cache_sigtramp((unsigned long) tramp); */
2331 return err;
2332}
2333
2334static inline int
2335setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2336{
2337 int err = 0;
2338
thsb5dc7732008-06-27 10:02:35 +00002339 err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002340
thsb5dc7732008-06-27 10:02:35 +00002341#define save_gp_reg(i) do { \
2342 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002343 } while(0)
2344 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
2345 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
2346 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
2347 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
2348 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
2349 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
2350 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
2351 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
2352 save_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002353#undef save_gp_reg
bellard106ec872006-06-27 21:08:10 +00002354
thsb5dc7732008-06-27 10:02:35 +00002355 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2356 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002357
2358 /* Not used yet, but might be useful if we ever have DSP suppport */
2359#if 0
2360 if (cpu_has_dsp) {
2361 err |= __put_user(mfhi1(), &sc->sc_hi1);
2362 err |= __put_user(mflo1(), &sc->sc_lo1);
2363 err |= __put_user(mfhi2(), &sc->sc_hi2);
2364 err |= __put_user(mflo2(), &sc->sc_lo2);
2365 err |= __put_user(mfhi3(), &sc->sc_hi3);
2366 err |= __put_user(mflo3(), &sc->sc_lo3);
2367 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2368 }
2369 /* same with 64 bit */
ths388bb212007-05-13 13:58:00 +00002370#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002371 err |= __put_user(regs->hi, &sc->sc_hi[0]);
2372 err |= __put_user(regs->lo, &sc->sc_lo[0]);
2373 if (cpu_has_dsp) {
2374 err |= __put_user(mfhi1(), &sc->sc_hi[1]);
2375 err |= __put_user(mflo1(), &sc->sc_lo[1]);
2376 err |= __put_user(mfhi2(), &sc->sc_hi[2]);
2377 err |= __put_user(mflo2(), &sc->sc_lo[2]);
2378 err |= __put_user(mfhi3(), &sc->sc_hi[3]);
2379 err |= __put_user(mflo3(), &sc->sc_lo[3]);
2380 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2381 }
ths388bb212007-05-13 13:58:00 +00002382#endif
2383#endif
bellard106ec872006-06-27 21:08:10 +00002384
ths388bb212007-05-13 13:58:00 +00002385#if 0
bellard106ec872006-06-27 21:08:10 +00002386 err |= __put_user(!!used_math(), &sc->sc_used_math);
2387
2388 if (!used_math())
2389 goto out;
2390
2391 /*
2392 * Save FPU state to signal context. Signal handler will "inherit"
2393 * current FPU state.
2394 */
2395 preempt_disable();
2396
2397 if (!is_fpu_owner()) {
2398 own_fpu();
2399 restore_fp(current);
2400 }
2401 err |= save_fp_context(sc);
2402
2403 preempt_enable();
2404 out:
2405#endif
2406 return err;
2407}
2408
2409static inline int
2410restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2411{
2412 int err = 0;
2413
2414 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2415
thsb5dc7732008-06-27 10:02:35 +00002416 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2417 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002418
thsead93602007-09-06 00:18:15 +00002419#define restore_gp_reg(i) do { \
thsb5dc7732008-06-27 10:02:35 +00002420 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002421 } while(0)
2422 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
2423 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
2424 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
2425 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
2426 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
2427 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
2428 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
2429 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
2430 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
2431 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
2432 restore_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002433#undef restore_gp_reg
bellard106ec872006-06-27 21:08:10 +00002434
2435#if 0
2436 if (cpu_has_dsp) {
2437 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
2438 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
2439 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
2440 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
2441 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
2442 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2443 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2444 }
ths388bb212007-05-13 13:58:00 +00002445#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002446 err |= __get_user(regs->hi, &sc->sc_hi[0]);
2447 err |= __get_user(regs->lo, &sc->sc_lo[0]);
2448 if (cpu_has_dsp) {
2449 err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
2450 err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
2451 err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
2452 err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
2453 err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
2454 err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
2455 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2456 }
ths388bb212007-05-13 13:58:00 +00002457#endif
bellard106ec872006-06-27 21:08:10 +00002458
2459 err |= __get_user(used_math, &sc->sc_used_math);
2460 conditional_used_math(used_math);
2461
2462 preempt_disable();
2463
2464 if (used_math()) {
2465 /* restore fpu context if we have used it before */
2466 own_fpu();
2467 err |= restore_fp_context(sc);
2468 } else {
2469 /* signal handler may have used FPU. Give it up. */
2470 lose_fpu();
2471 }
2472
2473 preempt_enable();
2474#endif
2475 return err;
2476}
2477/*
2478 * Determine which stack to use..
2479 */
bellard579a97f2007-11-11 14:26:47 +00002480static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00002481get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002482{
2483 unsigned long sp;
2484
2485 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002486 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002487
2488 /*
2489 * FPU emulator may have it's own trampoline active just
2490 * above the user stack, 16-bytes before the next lowest
2491 * 16 byte boundary. Try to avoid trashing it.
2492 */
2493 sp -= 32;
2494
bellard106ec872006-06-27 21:08:10 +00002495 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002496 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002497 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2498 }
bellard106ec872006-06-27 21:08:10 +00002499
bellard579a97f2007-11-11 14:26:47 +00002500 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002501}
2502
bellard579a97f2007-11-11 14:26:47 +00002503/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002504static void setup_frame(int sig, struct target_sigaction * ka,
bellard579a97f2007-11-11 14:26:47 +00002505 target_sigset_t *set, CPUState *regs)
bellard106ec872006-06-27 21:08:10 +00002506{
2507 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002508 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002509 int i;
2510
bellard579a97f2007-11-11 14:26:47 +00002511 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2512 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002513 goto give_sigsegv;
2514
2515 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2516
2517 if(setup_sigcontext(regs, &frame->sf_sc))
2518 goto give_sigsegv;
2519
2520 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2521 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2522 goto give_sigsegv;
2523 }
2524
2525 /*
2526 * Arguments to signal handler:
2527 *
2528 * a0 = signal number
2529 * a1 = 0 (should be cause)
2530 * a2 = pointer to struct sigcontext
2531 *
2532 * $25 and PC point to the signal handler, $29 points to the
2533 * struct sigframe.
2534 */
thsb5dc7732008-06-27 10:02:35 +00002535 regs->active_tc.gpr[ 4] = sig;
2536 regs->active_tc.gpr[ 5] = 0;
2537 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2538 regs->active_tc.gpr[29] = frame_addr;
2539 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002540 /* The original kernel code sets CP0_EPC to the handler
2541 * since it returns to userland using eret
2542 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002543 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
bellard579a97f2007-11-11 14:26:47 +00002544 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002545 return;
2546
2547give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002548 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002549 force_sig(TARGET_SIGSEGV/*, current*/);
ths5fafdf22007-09-16 21:08:06 +00002550 return;
bellard106ec872006-06-27 21:08:10 +00002551}
2552
2553long do_sigreturn(CPUState *regs)
2554{
ths388bb212007-05-13 13:58:00 +00002555 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002556 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002557 sigset_t blocked;
2558 target_sigset_t target_set;
2559 int i;
bellard106ec872006-06-27 21:08:10 +00002560
2561#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002562 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002563#endif
thsb5dc7732008-06-27 10:02:35 +00002564 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002565 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002566 goto badframe;
2567
ths388bb212007-05-13 13:58:00 +00002568 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002569 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2570 goto badframe;
ths388bb212007-05-13 13:58:00 +00002571 }
bellard106ec872006-06-27 21:08:10 +00002572
ths388bb212007-05-13 13:58:00 +00002573 target_to_host_sigset_internal(&blocked, &target_set);
2574 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002575
ths388bb212007-05-13 13:58:00 +00002576 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002577 goto badframe;
2578
2579#if 0
ths388bb212007-05-13 13:58:00 +00002580 /*
2581 * Don't let your children do this ...
2582 */
2583 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002584 "move\t$29, %0\n\t"
2585 "j\tsyscall_exit"
2586 :/* no outputs */
2587 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002588 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002589#endif
ths3b46e622007-09-17 08:09:54 +00002590
thsb5dc7732008-06-27 10:02:35 +00002591 regs->active_tc.PC = regs->CP0_EPC;
ths388bb212007-05-13 13:58:00 +00002592 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002593 * maybe a problem with nested signals ? */
2594 regs->CP0_EPC = 0;
2595 return 0;
2596
2597badframe:
ths388bb212007-05-13 13:58:00 +00002598 force_sig(TARGET_SIGSEGV/*, current*/);
2599 return 0;
bellard106ec872006-06-27 21:08:10 +00002600}
2601
pbrook624f7972008-05-31 16:11:38 +00002602static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard106ec872006-06-27 21:08:10 +00002603 target_siginfo_t *info,
2604 target_sigset_t *set, CPUState *env)
2605{
2606 fprintf(stderr, "setup_rt_frame: not implemented\n");
2607}
2608
2609long do_rt_sigreturn(CPUState *env)
2610{
2611 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002612 return -TARGET_ENOSYS;
bellard106ec872006-06-27 21:08:10 +00002613}
bellard6d5e2162004-09-30 22:04:13 +00002614
thsc3b5bc82007-12-02 06:31:25 +00002615#elif defined(TARGET_SH4)
2616
2617/*
2618 * code and data structures from linux kernel:
2619 * include/asm-sh/sigcontext.h
2620 * arch/sh/kernel/signal.c
2621 */
2622
2623struct target_sigcontext {
2624 target_ulong oldmask;
2625
2626 /* CPU registers */
2627 target_ulong sc_gregs[16];
2628 target_ulong sc_pc;
2629 target_ulong sc_pr;
2630 target_ulong sc_sr;
2631 target_ulong sc_gbr;
2632 target_ulong sc_mach;
2633 target_ulong sc_macl;
2634
2635 /* FPU registers */
2636 target_ulong sc_fpregs[16];
2637 target_ulong sc_xfpregs[16];
2638 unsigned int sc_fpscr;
2639 unsigned int sc_fpul;
2640 unsigned int sc_ownedfp;
2641};
2642
2643struct target_sigframe
2644{
2645 struct target_sigcontext sc;
2646 target_ulong extramask[TARGET_NSIG_WORDS-1];
2647 uint16_t retcode[3];
2648};
2649
2650
2651struct target_ucontext {
2652 target_ulong uc_flags;
2653 struct target_ucontext *uc_link;
2654 target_stack_t uc_stack;
2655 struct target_sigcontext uc_mcontext;
2656 target_sigset_t uc_sigmask; /* mask last for extensibility */
2657};
2658
2659struct target_rt_sigframe
2660{
2661 struct target_siginfo info;
2662 struct target_ucontext uc;
2663 uint16_t retcode[3];
2664};
2665
2666
2667#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
2668#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
2669
pbrook624f7972008-05-31 16:11:38 +00002670static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002671 unsigned long sp, size_t frame_size)
2672{
pbrook624f7972008-05-31 16:11:38 +00002673 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00002674 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2675 }
2676
2677 return (sp - frame_size) & -8ul;
2678}
2679
2680static int setup_sigcontext(struct target_sigcontext *sc,
2681 CPUState *regs, unsigned long mask)
2682{
2683 int err = 0;
2684
2685#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
2686 COPY(gregs[0]); COPY(gregs[1]);
2687 COPY(gregs[2]); COPY(gregs[3]);
2688 COPY(gregs[4]); COPY(gregs[5]);
2689 COPY(gregs[6]); COPY(gregs[7]);
2690 COPY(gregs[8]); COPY(gregs[9]);
2691 COPY(gregs[10]); COPY(gregs[11]);
2692 COPY(gregs[12]); COPY(gregs[13]);
2693 COPY(gregs[14]); COPY(gregs[15]);
2694 COPY(gbr); COPY(mach);
2695 COPY(macl); COPY(pr);
2696 COPY(sr); COPY(pc);
2697#undef COPY
2698
2699 /* todo: save FPU registers here */
2700
2701 /* non-iBCS2 extensions.. */
2702 err |= __put_user(mask, &sc->oldmask);
2703
2704 return err;
2705}
2706
pbrookc2764712009-03-07 15:24:59 +00002707static int restore_sigcontext(CPUState *regs,
thsc3b5bc82007-12-02 06:31:25 +00002708 struct target_sigcontext *sc)
2709{
2710 unsigned int err = 0;
2711
2712#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
2713 COPY(gregs[1]);
2714 COPY(gregs[2]); COPY(gregs[3]);
2715 COPY(gregs[4]); COPY(gregs[5]);
2716 COPY(gregs[6]); COPY(gregs[7]);
2717 COPY(gregs[8]); COPY(gregs[9]);
2718 COPY(gregs[10]); COPY(gregs[11]);
2719 COPY(gregs[12]); COPY(gregs[13]);
2720 COPY(gregs[14]); COPY(gregs[15]);
2721 COPY(gbr); COPY(mach);
2722 COPY(macl); COPY(pr);
2723 COPY(sr); COPY(pc);
2724#undef COPY
2725
2726 /* todo: restore FPU registers here */
2727
2728 regs->tra = -1; /* disable syscall checks */
2729 return err;
2730}
2731
pbrook624f7972008-05-31 16:11:38 +00002732static void setup_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002733 target_sigset_t *set, CPUState *regs)
2734{
2735 struct target_sigframe *frame;
2736 abi_ulong frame_addr;
2737 int i;
2738 int err = 0;
2739 int signal;
2740
2741 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2742 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2743 goto give_sigsegv;
2744
2745 signal = current_exec_domain_sig(sig);
2746
2747 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
2748
2749 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2750 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
2751 }
2752
2753 /* Set up to return from userspace. If provided, use a stub
2754 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002755 if (ka->sa_flags & TARGET_SA_RESTORER) {
2756 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002757 } else {
2758 /* Generate return code (system call to sigreturn) */
2759 err |= __put_user(MOVW(2), &frame->retcode[0]);
2760 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2761 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
2762 regs->pr = (unsigned long) frame->retcode;
2763 }
2764
2765 if (err)
2766 goto give_sigsegv;
2767
2768 /* Set up registers for signal handler */
2769 regs->gregs[15] = (unsigned long) frame;
2770 regs->gregs[4] = signal; /* Arg for signal handler */
2771 regs->gregs[5] = 0;
2772 regs->gregs[6] = (unsigned long) &frame->sc;
pbrook624f7972008-05-31 16:11:38 +00002773 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002774
2775 unlock_user_struct(frame, frame_addr, 1);
2776 return;
2777
2778give_sigsegv:
2779 unlock_user_struct(frame, frame_addr, 1);
2780 force_sig(SIGSEGV);
2781}
2782
pbrook624f7972008-05-31 16:11:38 +00002783static void setup_rt_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002784 target_siginfo_t *info,
2785 target_sigset_t *set, CPUState *regs)
2786{
2787 struct target_rt_sigframe *frame;
2788 abi_ulong frame_addr;
2789 int i;
2790 int err = 0;
2791 int signal;
2792
2793 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2794 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2795 goto give_sigsegv;
2796
2797 signal = current_exec_domain_sig(sig);
2798
2799 err |= copy_siginfo_to_user(&frame->info, info);
2800
2801 /* Create the ucontext. */
2802 err |= __put_user(0, &frame->uc.uc_flags);
2803 err |= __put_user(0, (unsigned long *)&frame->uc.uc_link);
balrog526ccb72008-07-16 12:13:52 +00002804 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
thsc3b5bc82007-12-02 06:31:25 +00002805 &frame->uc.uc_stack.ss_sp);
2806 err |= __put_user(sas_ss_flags(regs->gregs[15]),
2807 &frame->uc.uc_stack.ss_flags);
2808 err |= __put_user(target_sigaltstack_used.ss_size,
2809 &frame->uc.uc_stack.ss_size);
2810 err |= setup_sigcontext(&frame->uc.uc_mcontext,
2811 regs, set->sig[0]);
2812 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2813 err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]);
2814 }
2815
2816 /* Set up to return from userspace. If provided, use a stub
2817 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002818 if (ka->sa_flags & TARGET_SA_RESTORER) {
2819 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002820 } else {
2821 /* Generate return code (system call to sigreturn) */
2822 err |= __put_user(MOVW(2), &frame->retcode[0]);
2823 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2824 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
2825 regs->pr = (unsigned long) frame->retcode;
2826 }
2827
2828 if (err)
2829 goto give_sigsegv;
2830
2831 /* Set up registers for signal handler */
2832 regs->gregs[15] = (unsigned long) frame;
2833 regs->gregs[4] = signal; /* Arg for signal handler */
2834 regs->gregs[5] = (unsigned long) &frame->info;
2835 regs->gregs[6] = (unsigned long) &frame->uc;
pbrook624f7972008-05-31 16:11:38 +00002836 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002837
2838 unlock_user_struct(frame, frame_addr, 1);
2839 return;
2840
2841give_sigsegv:
2842 unlock_user_struct(frame, frame_addr, 1);
2843 force_sig(SIGSEGV);
2844}
2845
2846long do_sigreturn(CPUState *regs)
2847{
2848 struct target_sigframe *frame;
2849 abi_ulong frame_addr;
2850 sigset_t blocked;
2851 target_sigset_t target_set;
2852 int i;
2853 int err = 0;
2854
2855#if defined(DEBUG_SIGNAL)
2856 fprintf(stderr, "do_sigreturn\n");
2857#endif
2858 frame_addr = regs->gregs[15];
2859 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2860 goto badframe;
2861
2862 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
2863 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2864 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
2865 }
2866
2867 if (err)
2868 goto badframe;
2869
2870 target_to_host_sigset_internal(&blocked, &target_set);
2871 sigprocmask(SIG_SETMASK, &blocked, NULL);
2872
2873 if (restore_sigcontext(regs, &frame->sc))
2874 goto badframe;
2875
2876 unlock_user_struct(frame, frame_addr, 0);
2877 return regs->gregs[0];
2878
2879badframe:
2880 unlock_user_struct(frame, frame_addr, 0);
2881 force_sig(TARGET_SIGSEGV);
2882 return 0;
2883}
2884
2885long do_rt_sigreturn(CPUState *regs)
2886{
2887 struct target_rt_sigframe *frame;
2888 abi_ulong frame_addr;
2889 sigset_t blocked;
2890
2891#if defined(DEBUG_SIGNAL)
2892 fprintf(stderr, "do_rt_sigreturn\n");
2893#endif
2894 frame_addr = regs->gregs[15];
2895 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2896 goto badframe;
2897
2898 target_to_host_sigset(&blocked, &frame->uc.uc_sigmask);
2899 sigprocmask(SIG_SETMASK, &blocked, NULL);
2900
2901 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
2902 goto badframe;
2903
2904 if (do_sigaltstack(frame_addr +
2905 offsetof(struct target_rt_sigframe, uc.uc_stack),
2906 0, get_sp_from_cpustate(regs)) == -EFAULT)
2907 goto badframe;
2908
2909 unlock_user_struct(frame, frame_addr, 0);
2910 return regs->gregs[0];
2911
2912badframe:
2913 unlock_user_struct(frame, frame_addr, 0);
2914 force_sig(TARGET_SIGSEGV);
2915 return 0;
2916}
edgar_iglb6d3abd2008-02-28 11:29:27 +00002917#elif defined(TARGET_CRIS)
2918
2919struct target_sigcontext {
2920 struct target_pt_regs regs; /* needs to be first */
2921 uint32_t oldmask;
2922 uint32_t usp; /* usp before stacking this gunk on it */
2923};
2924
2925/* Signal frames. */
2926struct target_signal_frame {
2927 struct target_sigcontext sc;
2928 uint32_t extramask[TARGET_NSIG_WORDS - 1];
2929 uint8_t retcode[8]; /* Trampoline code. */
2930};
2931
2932struct rt_signal_frame {
2933 struct siginfo *pinfo;
2934 void *puc;
2935 struct siginfo info;
2936 struct ucontext uc;
2937 uint8_t retcode[8]; /* Trampoline code. */
2938};
2939
2940static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
2941{
edgar_igl9664d922008-03-03 22:23:53 +00002942 __put_user(env->regs[0], &sc->regs.r0);
2943 __put_user(env->regs[1], &sc->regs.r1);
2944 __put_user(env->regs[2], &sc->regs.r2);
2945 __put_user(env->regs[3], &sc->regs.r3);
2946 __put_user(env->regs[4], &sc->regs.r4);
2947 __put_user(env->regs[5], &sc->regs.r5);
2948 __put_user(env->regs[6], &sc->regs.r6);
2949 __put_user(env->regs[7], &sc->regs.r7);
2950 __put_user(env->regs[8], &sc->regs.r8);
2951 __put_user(env->regs[9], &sc->regs.r9);
2952 __put_user(env->regs[10], &sc->regs.r10);
2953 __put_user(env->regs[11], &sc->regs.r11);
2954 __put_user(env->regs[12], &sc->regs.r12);
2955 __put_user(env->regs[13], &sc->regs.r13);
2956 __put_user(env->regs[14], &sc->usp);
2957 __put_user(env->regs[15], &sc->regs.acr);
2958 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
2959 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
2960 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002961}
edgar_igl9664d922008-03-03 22:23:53 +00002962
edgar_iglb6d3abd2008-02-28 11:29:27 +00002963static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
2964{
edgar_igl9664d922008-03-03 22:23:53 +00002965 __get_user(env->regs[0], &sc->regs.r0);
2966 __get_user(env->regs[1], &sc->regs.r1);
2967 __get_user(env->regs[2], &sc->regs.r2);
2968 __get_user(env->regs[3], &sc->regs.r3);
2969 __get_user(env->regs[4], &sc->regs.r4);
2970 __get_user(env->regs[5], &sc->regs.r5);
2971 __get_user(env->regs[6], &sc->regs.r6);
2972 __get_user(env->regs[7], &sc->regs.r7);
2973 __get_user(env->regs[8], &sc->regs.r8);
2974 __get_user(env->regs[9], &sc->regs.r9);
2975 __get_user(env->regs[10], &sc->regs.r10);
2976 __get_user(env->regs[11], &sc->regs.r11);
2977 __get_user(env->regs[12], &sc->regs.r12);
2978 __get_user(env->regs[13], &sc->regs.r13);
2979 __get_user(env->regs[14], &sc->usp);
2980 __get_user(env->regs[15], &sc->regs.acr);
2981 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
2982 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
2983 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002984}
2985
edgar_igl9664d922008-03-03 22:23:53 +00002986static abi_ulong get_sigframe(CPUState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00002987{
edgar_igl9664d922008-03-03 22:23:53 +00002988 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002989 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00002990 sp = (env->regs[R_SP] & ~3);
2991 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002992}
2993
pbrook624f7972008-05-31 16:11:38 +00002994static void setup_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00002995 target_sigset_t *set, CPUState *env)
2996{
2997 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00002998 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002999 int err = 0;
3000 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003001
edgar_igl9664d922008-03-03 22:23:53 +00003002 frame_addr = get_sigframe(env, sizeof *frame);
3003 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003004 goto badframe;
3005
3006 /*
3007 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3008 * use this trampoline anymore but it sets it up for GDB.
3009 * In QEMU, using the trampoline simplifies things a bit so we use it.
3010 *
3011 * This is movu.w __NR_sigreturn, r9; break 13;
3012 */
3013 err |= __put_user(0x9c5f, frame->retcode+0);
3014 err |= __put_user(TARGET_NR_sigreturn,
3015 frame->retcode+2);
3016 err |= __put_user(0xe93d, frame->retcode+4);
3017
3018 /* Save the mask. */
3019 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3020 if (err)
3021 goto badframe;
3022
3023 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3024 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3025 goto badframe;
3026 }
3027
3028 setup_sigcontext(&frame->sc, env);
3029
3030 /* Move the stack and setup the arguments for the handler. */
balrog526ccb72008-07-16 12:13:52 +00003031 env->regs[R_SP] = (uint32_t) (unsigned long) frame;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003032 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003033 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003034 /* Link SRP so the guest returns through the trampoline. */
balrog526ccb72008-07-16 12:13:52 +00003035 env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003036
edgar_igl9664d922008-03-03 22:23:53 +00003037 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003038 return;
3039 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003040 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003041 force_sig(TARGET_SIGSEGV);
3042}
3043
pbrook624f7972008-05-31 16:11:38 +00003044static void setup_rt_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00003045 target_siginfo_t *info,
3046 target_sigset_t *set, CPUState *env)
3047{
3048 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3049}
3050
3051long do_sigreturn(CPUState *env)
3052{
3053 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003054 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003055 target_sigset_t target_set;
3056 sigset_t set;
3057 int i;
3058
edgar_igl9664d922008-03-03 22:23:53 +00003059 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003060 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003061 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003062 goto badframe;
3063
3064 /* Restore blocked signals */
3065 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3066 goto badframe;
3067 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3068 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3069 goto badframe;
3070 }
3071 target_to_host_sigset_internal(&set, &target_set);
3072 sigprocmask(SIG_SETMASK, &set, NULL);
3073
3074 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003075 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003076 return env->regs[10];
3077 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003078 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003079 force_sig(TARGET_SIGSEGV);
3080}
3081
3082long do_rt_sigreturn(CPUState *env)
3083{
3084 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3085 return -TARGET_ENOSYS;
3086}
thsc3b5bc82007-12-02 06:31:25 +00003087
bellardb346ff42003-06-15 20:05:50 +00003088#else
3089
pbrook624f7972008-05-31 16:11:38 +00003090static void setup_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003091 target_sigset_t *set, CPUState *env)
3092{
3093 fprintf(stderr, "setup_frame: not implemented\n");
3094}
3095
pbrook624f7972008-05-31 16:11:38 +00003096static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003097 target_siginfo_t *info,
3098 target_sigset_t *set, CPUState *env)
3099{
3100 fprintf(stderr, "setup_rt_frame: not implemented\n");
3101}
3102
3103long do_sigreturn(CPUState *env)
3104{
3105 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003106 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003107}
3108
3109long do_rt_sigreturn(CPUState *env)
3110{
3111 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003112 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003113}
3114
bellard66fb9762003-03-23 01:06:05 +00003115#endif
3116
pbrook624f7972008-05-31 16:11:38 +00003117void process_pending_signals(CPUState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00003118{
3119 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00003120 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00003121 sigset_t set, old_set;
3122 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00003123 struct emulated_sigtable *k;
3124 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00003125 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00003126 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00003127
pbrook624f7972008-05-31 16:11:38 +00003128 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00003129 return;
3130
pbrook624f7972008-05-31 16:11:38 +00003131 /* FIXME: This is not threadsafe. */
3132 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00003133 for(sig = 1; sig <= TARGET_NSIG; sig++) {
3134 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00003135 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00003136 k++;
bellard31e31b82003-02-18 22:55:36 +00003137 }
3138 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00003139 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00003140 return;
bellard66fb9762003-03-23 01:06:05 +00003141
bellard31e31b82003-02-18 22:55:36 +00003142 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00003143#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00003144 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00003145#endif
3146 /* dequeue signal */
3147 q = k->first;
3148 k->first = q->next;
3149 if (!k->first)
3150 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00003151
bellard1fddef42005-04-17 19:16:13 +00003152 sig = gdb_handlesig (cpu_env, sig);
3153 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00003154 sa = NULL;
3155 handler = TARGET_SIG_IGN;
3156 } else {
3157 sa = &sigact_table[sig - 1];
3158 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00003159 }
bellard66fb9762003-03-23 01:06:05 +00003160
bellard66fb9762003-03-23 01:06:05 +00003161 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00003162 /* default handler : ignore some signal. The other are job control or fatal */
3163 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
3164 kill(getpid(),SIGSTOP);
3165 } else if (sig != TARGET_SIGCHLD &&
3166 sig != TARGET_SIGURG &&
3167 sig != TARGET_SIGWINCH &&
3168 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00003169 force_sig(sig);
3170 }
3171 } else if (handler == TARGET_SIG_IGN) {
3172 /* ignore sig */
3173 } else if (handler == TARGET_SIG_ERR) {
3174 force_sig(sig);
3175 } else {
bellard9de5e442003-03-23 16:49:39 +00003176 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00003177 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00003178 /* SA_NODEFER indicates that the current signal should not be
3179 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00003180 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00003181 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00003182
bellard9de5e442003-03-23 16:49:39 +00003183 /* block signals in the handler using Linux */
3184 sigprocmask(SIG_BLOCK, &set, &old_set);
3185 /* save the previous blocked signal state to restore it at the
3186 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00003187 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00003188
bellardbc8a22c2003-03-30 21:02:40 +00003189 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00003190#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00003191 {
3192 CPUX86State *env = cpu_env;
3193 if (env->eflags & VM_MASK)
3194 save_v86_state(env);
3195 }
3196#endif
bellard9de5e442003-03-23 16:49:39 +00003197 /* prepare the stack frame of the virtual CPU */
pbrook624f7972008-05-31 16:11:38 +00003198 if (sa->sa_flags & TARGET_SA_SIGINFO)
3199 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00003200 else
pbrook624f7972008-05-31 16:11:38 +00003201 setup_frame(sig, sa, &target_old_set, cpu_env);
3202 if (sa->sa_flags & TARGET_SA_RESETHAND)
3203 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00003204 }
bellard66fb9762003-03-23 01:06:05 +00003205 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00003206 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00003207}