blob: c3f73812897f4c5cd3c38f413a75d8221e991faf [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>
bellard31e31b82003-02-18 22:55:36 +000028#include <sys/ucontext.h>
29
bellard3ef693a2003-03-23 20:17:16 +000030#include "qemu.h"
blueswir1992f48a2007-10-14 16:27:31 +000031#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000032
33//#define DEBUG_SIGNAL
34
blueswir1249c4c32008-10-05 11:09:37 +000035static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000036 .ss_sp = 0,
37 .ss_size = 0,
38 .ss_flags = TARGET_SS_DISABLE,
39};
40
pbrook624f7972008-05-31 16:11:38 +000041static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000042
ths5fafdf22007-09-16 21:08:06 +000043static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000044 void *puc);
45
bellard9e5f5282003-07-13 17:33:54 +000046static uint8_t host_to_target_signal_table[65] = {
47 [SIGHUP] = TARGET_SIGHUP,
48 [SIGINT] = TARGET_SIGINT,
49 [SIGQUIT] = TARGET_SIGQUIT,
50 [SIGILL] = TARGET_SIGILL,
51 [SIGTRAP] = TARGET_SIGTRAP,
52 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000053/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000054 [SIGBUS] = TARGET_SIGBUS,
55 [SIGFPE] = TARGET_SIGFPE,
56 [SIGKILL] = TARGET_SIGKILL,
57 [SIGUSR1] = TARGET_SIGUSR1,
58 [SIGSEGV] = TARGET_SIGSEGV,
59 [SIGUSR2] = TARGET_SIGUSR2,
60 [SIGPIPE] = TARGET_SIGPIPE,
61 [SIGALRM] = TARGET_SIGALRM,
62 [SIGTERM] = TARGET_SIGTERM,
63#ifdef SIGSTKFLT
64 [SIGSTKFLT] = TARGET_SIGSTKFLT,
65#endif
66 [SIGCHLD] = TARGET_SIGCHLD,
67 [SIGCONT] = TARGET_SIGCONT,
68 [SIGSTOP] = TARGET_SIGSTOP,
69 [SIGTSTP] = TARGET_SIGTSTP,
70 [SIGTTIN] = TARGET_SIGTTIN,
71 [SIGTTOU] = TARGET_SIGTTOU,
72 [SIGURG] = TARGET_SIGURG,
73 [SIGXCPU] = TARGET_SIGXCPU,
74 [SIGXFSZ] = TARGET_SIGXFSZ,
75 [SIGVTALRM] = TARGET_SIGVTALRM,
76 [SIGPROF] = TARGET_SIGPROF,
77 [SIGWINCH] = TARGET_SIGWINCH,
78 [SIGIO] = TARGET_SIGIO,
79 [SIGPWR] = TARGET_SIGPWR,
80 [SIGSYS] = TARGET_SIGSYS,
81 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000082 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
83 host libpthread signals. This assumes noone actually uses SIGRTMAX :-/
84 To fix this properly we need to do manual signal delivery multiplexed
85 over a single host signal. */
86 [__SIGRTMIN] = __SIGRTMAX,
87 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000088};
89static uint8_t target_to_host_signal_table[65];
90
thsa04e1342007-09-27 13:57:58 +000091static inline int on_sig_stack(unsigned long sp)
92{
93 return (sp - target_sigaltstack_used.ss_sp
94 < target_sigaltstack_used.ss_size);
95}
96
97static inline int sas_ss_flags(unsigned long sp)
98{
99 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
100 : on_sig_stack(sp) ? SS_ONSTACK : 0);
101}
102
bellard31e31b82003-02-18 22:55:36 +0000103static inline int host_to_target_signal(int sig)
104{
pbrook4cb05962008-05-30 18:05:19 +0000105 if (sig > 64)
106 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000107 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
pbrook4cb05962008-05-30 18:05:19 +0000110int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000111{
pbrook4cb05962008-05-30 18:05:19 +0000112 if (sig > 64)
113 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000114 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000115}
116
pbrookf5545b52008-05-30 22:37:07 +0000117static inline void target_sigemptyset(target_sigset_t *set)
118{
119 memset(set, 0, sizeof(*set));
120}
121
122static inline void target_sigaddset(target_sigset_t *set, int signum)
123{
124 signum--;
125 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
126 set->sig[signum / TARGET_NSIG_BPW] |= mask;
127}
128
129static inline int target_sigismember(const target_sigset_t *set, int signum)
130{
131 signum--;
132 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
133 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
134}
135
ths5fafdf22007-09-16 21:08:06 +0000136static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000137 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000138{
139 int i;
pbrookf5545b52008-05-30 22:37:07 +0000140 target_sigemptyset(d);
141 for (i = 1; i <= TARGET_NSIG; i++) {
142 if (sigismember(s, i)) {
143 target_sigaddset(d, host_to_target_signal(i));
144 }
bellard9e5f5282003-07-13 17:33:54 +0000145 }
bellard66fb9762003-03-23 01:06:05 +0000146}
147
bellard92319442004-06-19 16:58:13 +0000148void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
149{
150 target_sigset_t d1;
151 int i;
152
153 host_to_target_sigset_internal(&d1, s);
154 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000155 d->sig[i] = tswapl(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000156}
157
blueswir18fcd3692008-08-17 20:26:25 +0000158static void target_to_host_sigset_internal(sigset_t *d,
159 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000160{
161 int i;
pbrookf5545b52008-05-30 22:37:07 +0000162 sigemptyset(d);
163 for (i = 1; i <= TARGET_NSIG; i++) {
164 if (target_sigismember(s, i)) {
165 sigaddset(d, target_to_host_signal(i));
166 }
167 }
bellard66fb9762003-03-23 01:06:05 +0000168}
169
bellard92319442004-06-19 16:58:13 +0000170void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
171{
172 target_sigset_t s1;
173 int i;
174
175 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000176 s1.sig[i] = tswapl(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000177 target_to_host_sigset_internal(d, &s1);
178}
ths3b46e622007-09-17 08:09:54 +0000179
blueswir1992f48a2007-10-14 16:27:31 +0000180void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000181 const sigset_t *sigset)
182{
bellard9e5f5282003-07-13 17:33:54 +0000183 target_sigset_t d;
184 host_to_target_sigset(&d, sigset);
185 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000186}
187
ths5fafdf22007-09-16 21:08:06 +0000188void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000189 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000190{
bellard9e5f5282003-07-13 17:33:54 +0000191 target_sigset_t d;
192 int i;
193
194 d.sig[0] = *old_sigset;
195 for(i = 1;i < TARGET_NSIG_WORDS; i++)
196 d.sig[i] = 0;
197 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000198}
199
bellard9de5e442003-03-23 16:49:39 +0000200/* siginfo conversion */
201
ths5fafdf22007-09-16 21:08:06 +0000202static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000203 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000204{
bellard9de5e442003-03-23 16:49:39 +0000205 int sig;
206 sig = host_to_target_signal(info->si_signo);
207 tinfo->si_signo = sig;
208 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000209 tinfo->si_code = info->si_code;
ths5fafdf22007-09-16 21:08:06 +0000210 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000211 sig == SIGBUS || sig == SIGTRAP) {
bellard9de5e442003-03-23 16:49:39 +0000212 /* should never come here, but who knows. The information for
213 the target is irrelevant */
214 tinfo->_sifields._sigfault._addr = 0;
ths7f7f7c82007-07-12 11:02:46 +0000215 } else if (sig == SIGIO) {
216 tinfo->_sifields._sigpoll._fd = info->si_fd;
bellard9de5e442003-03-23 16:49:39 +0000217 } else if (sig >= TARGET_SIGRTMIN) {
218 tinfo->_sifields._rt._pid = info->si_pid;
219 tinfo->_sifields._rt._uid = info->si_uid;
220 /* XXX: potential problem if 64 bit */
ths5fafdf22007-09-16 21:08:06 +0000221 tinfo->_sifields._rt._sigval.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000222 (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000223 }
bellard66fb9762003-03-23 01:06:05 +0000224}
225
ths5fafdf22007-09-16 21:08:06 +0000226static void tswap_siginfo(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000227 const target_siginfo_t *info)
228{
229 int sig;
230 sig = info->si_signo;
231 tinfo->si_signo = tswap32(sig);
232 tinfo->si_errno = tswap32(info->si_errno);
233 tinfo->si_code = tswap32(info->si_code);
ths5fafdf22007-09-16 21:08:06 +0000234 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000235 sig == SIGBUS || sig == SIGTRAP) {
ths5fafdf22007-09-16 21:08:06 +0000236 tinfo->_sifields._sigfault._addr =
bellard9de5e442003-03-23 16:49:39 +0000237 tswapl(info->_sifields._sigfault._addr);
ths7f7f7c82007-07-12 11:02:46 +0000238 } else if (sig == SIGIO) {
239 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
bellard9de5e442003-03-23 16:49:39 +0000240 } else if (sig >= TARGET_SIGRTMIN) {
241 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
242 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000243 tinfo->_sifields._rt._sigval.sival_ptr =
bellard9de5e442003-03-23 16:49:39 +0000244 tswapl(info->_sifields._rt._sigval.sival_ptr);
245 }
246}
247
248
249void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
250{
251 host_to_target_siginfo_noswap(tinfo, info);
252 tswap_siginfo(tinfo, tinfo);
253}
254
255/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000256/* XXX: find a solution for 64 bit (additional malloced data is needed) */
bellard9de5e442003-03-23 16:49:39 +0000257void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000258{
259 info->si_signo = tswap32(tinfo->si_signo);
260 info->si_errno = tswap32(tinfo->si_errno);
261 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000262 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
263 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000264 info->si_value.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000265 (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000266}
267
aurel32ca587a82008-12-18 22:44:13 +0000268static int fatal_signal (int sig)
269{
270 switch (sig) {
271 case TARGET_SIGCHLD:
272 case TARGET_SIGURG:
273 case TARGET_SIGWINCH:
274 /* Ignored by default. */
275 return 0;
276 case TARGET_SIGCONT:
277 case TARGET_SIGSTOP:
278 case TARGET_SIGTSTP:
279 case TARGET_SIGTTIN:
280 case TARGET_SIGTTOU:
281 /* Job control signals. */
282 return 0;
283 default:
284 return 1;
285 }
286}
287
bellard31e31b82003-02-18 22:55:36 +0000288void signal_init(void)
289{
290 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000291 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000292 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000293 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000294
bellard9e5f5282003-07-13 17:33:54 +0000295 /* generate signal conversion tables */
296 for(i = 1; i <= 64; i++) {
297 if (host_to_target_signal_table[i] == 0)
298 host_to_target_signal_table[i] = i;
299 }
300 for(i = 1; i <= 64; i++) {
301 j = host_to_target_signal_table[i];
302 target_to_host_signal_table[j] = i;
303 }
ths3b46e622007-09-17 08:09:54 +0000304
bellard9de5e442003-03-23 16:49:39 +0000305 /* set all host signal handlers. ALL signals are blocked during
306 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000307 memset(sigact_table, 0, sizeof(sigact_table));
308
bellard9de5e442003-03-23 16:49:39 +0000309 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000310 act.sa_flags = SA_SIGINFO;
311 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000312 for(i = 1; i <= TARGET_NSIG; i++) {
313 host_sig = target_to_host_signal(i);
314 sigaction(host_sig, NULL, &oact);
315 if (oact.sa_sigaction == (void *)SIG_IGN) {
316 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
317 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
318 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
319 }
320 /* If there's already a handler installed then something has
321 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000322 /* Install some handlers for our own use. We need at least
323 SIGSEGV and SIGBUS, to detect exceptions. We can not just
324 trap all signals because it affects syscall interrupt
325 behavior. But do trap all default-fatal signals. */
326 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000327 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000328 }
bellard31e31b82003-02-18 22:55:36 +0000329}
330
bellard66fb9762003-03-23 01:06:05 +0000331/* signal queue handling */
332
pbrook624f7972008-05-31 16:11:38 +0000333static inline struct sigqueue *alloc_sigqueue(CPUState *env)
bellard66fb9762003-03-23 01:06:05 +0000334{
pbrook624f7972008-05-31 16:11:38 +0000335 TaskState *ts = env->opaque;
336 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000337 if (!q)
338 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000339 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000340 return q;
341}
342
pbrook624f7972008-05-31 16:11:38 +0000343static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000344{
pbrook624f7972008-05-31 16:11:38 +0000345 TaskState *ts = env->opaque;
346 q->next = ts->first_free;
347 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000348}
349
bellard9de5e442003-03-23 16:49:39 +0000350/* abort execution with signal */
blueswir18fcd3692008-08-17 20:26:25 +0000351static void __attribute((noreturn)) force_sig(int sig)
bellard66fb9762003-03-23 01:06:05 +0000352{
353 int host_sig;
bellard66fb9762003-03-23 01:06:05 +0000354 host_sig = target_to_host_signal(sig);
ths5fafdf22007-09-16 21:08:06 +0000355 fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
bellard66fb9762003-03-23 01:06:05 +0000356 sig, strsignal(host_sig));
bellard9de5e442003-03-23 16:49:39 +0000357#if 1
aurel32ca587a82008-12-18 22:44:13 +0000358 gdb_signalled(thread_env, sig);
bellard66fb9762003-03-23 01:06:05 +0000359 _exit(-host_sig);
bellard9de5e442003-03-23 16:49:39 +0000360#else
361 {
362 struct sigaction act;
363 sigemptyset(&act.sa_mask);
364 act.sa_flags = SA_SIGINFO;
365 act.sa_sigaction = SIG_DFL;
366 sigaction(SIGABRT, &act, NULL);
367 abort();
368 }
369#endif
bellard66fb9762003-03-23 01:06:05 +0000370}
371
bellard9de5e442003-03-23 16:49:39 +0000372/* queue a signal so that it will be send to the virtual CPU as soon
373 as possible */
pbrook624f7972008-05-31 16:11:38 +0000374int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000375{
pbrook624f7972008-05-31 16:11:38 +0000376 TaskState *ts = env->opaque;
377 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000378 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000379 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000380 int queue;
bellard66fb9762003-03-23 01:06:05 +0000381
bellard9de5e442003-03-23 16:49:39 +0000382#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000383 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000384 sig);
bellard66fb9762003-03-23 01:06:05 +0000385#endif
pbrook624f7972008-05-31 16:11:38 +0000386 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000387 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000388 handler = sigact_table[sig - 1]._sa_handler;
aurel32ca587a82008-12-18 22:44:13 +0000389 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000390 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
391 kill(getpid(),SIGSTOP);
392 return 0;
393 } else
bellard66fb9762003-03-23 01:06:05 +0000394 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000395 if (sig != TARGET_SIGCHLD &&
396 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000397 sig != TARGET_SIGWINCH &&
398 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000399 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000400 } else {
401 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000402 }
aurel32ca587a82008-12-18 22:44:13 +0000403 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000404 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000405 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000406 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000407 force_sig(sig);
408 } else {
bellard9de5e442003-03-23 16:49:39 +0000409 pq = &k->first;
410 if (sig < TARGET_SIGRTMIN) {
411 /* if non real time signal, we queue exactly one signal */
412 if (!k->pending)
413 q = &k->info;
414 else
415 return 0;
416 } else {
417 if (!k->pending) {
418 /* first signal */
419 q = &k->info;
420 } else {
pbrook624f7972008-05-31 16:11:38 +0000421 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000422 if (!q)
423 return -EAGAIN;
424 while (*pq != NULL)
425 pq = &(*pq)->next;
426 }
427 }
428 *pq = q;
429 q->info = *info;
430 q->next = NULL;
431 k->pending = 1;
432 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000433 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000434 return 1; /* indicates that the signal was queued */
435 }
436}
437
ths5fafdf22007-09-16 21:08:06 +0000438static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000439 void *puc)
440{
441 int sig;
442 target_siginfo_t tinfo;
443
444 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000445 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000446 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000447 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000448 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000449 return;
450 }
451
452 /* get target signal number */
453 sig = host_to_target_signal(host_signum);
454 if (sig < 1 || sig > TARGET_NSIG)
455 return;
456#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000457 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000458#endif
459 host_to_target_siginfo_noswap(&tinfo, info);
pbrookd5975362008-06-07 20:50:51 +0000460 if (queue_signal(thread_env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000461 /* interrupt the virtual CPU as soon as possible */
pbrookd5975362008-06-07 20:50:51 +0000462 cpu_interrupt(thread_env, CPU_INTERRUPT_EXIT);
bellard66fb9762003-03-23 01:06:05 +0000463 }
bellard31e31b82003-02-18 22:55:36 +0000464}
465
ths0da46a62007-10-20 20:23:07 +0000466/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000467/* compare linux/kernel/signal.c:do_sigaltstack() */
468abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000469{
470 int ret;
471 struct target_sigaltstack oss;
472
473 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000474 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000475 {
476 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
477 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
478 __put_user(sas_ss_flags(sp), &oss.ss_flags);
479 }
480
bellard579a97f2007-11-11 14:26:47 +0000481 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000482 {
bellard579a97f2007-11-11 14:26:47 +0000483 struct target_sigaltstack *uss;
484 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000485
ths0da46a62007-10-20 20:23:07 +0000486 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000487 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000488 || __get_user(ss.ss_sp, &uss->ss_sp)
489 || __get_user(ss.ss_size, &uss->ss_size)
490 || __get_user(ss.ss_flags, &uss->ss_flags))
491 goto out;
bellard579a97f2007-11-11 14:26:47 +0000492 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000493
ths0da46a62007-10-20 20:23:07 +0000494 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000495 if (on_sig_stack(sp))
496 goto out;
497
ths0da46a62007-10-20 20:23:07 +0000498 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000499 if (ss.ss_flags != TARGET_SS_DISABLE
500 && ss.ss_flags != TARGET_SS_ONSTACK
501 && ss.ss_flags != 0)
502 goto out;
503
504 if (ss.ss_flags == TARGET_SS_DISABLE) {
505 ss.ss_size = 0;
506 ss.ss_sp = 0;
507 } else {
ths0da46a62007-10-20 20:23:07 +0000508 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000509 if (ss.ss_size < MINSIGSTKSZ)
510 goto out;
511 }
512
513 target_sigaltstack_used.ss_sp = ss.ss_sp;
514 target_sigaltstack_used.ss_size = ss.ss_size;
515 }
516
bellard579a97f2007-11-11 14:26:47 +0000517 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000518 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000519 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000520 goto out;
thsa04e1342007-09-27 13:57:58 +0000521 }
522
523 ret = 0;
524out:
525 return ret;
526}
527
ths0da46a62007-10-20 20:23:07 +0000528/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000529int do_sigaction(int sig, const struct target_sigaction *act,
530 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000531{
pbrook624f7972008-05-31 16:11:38 +0000532 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000533 struct sigaction act1;
534 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000535 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000536
ths2a913eb2008-11-27 15:46:25 +0000537 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000538 return -EINVAL;
539 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000540#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000541 fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
bellard66fb9762003-03-23 01:06:05 +0000542 sig, (int)act, (int)oact);
543#endif
544 if (oact) {
pbrook624f7972008-05-31 16:11:38 +0000545 oact->_sa_handler = tswapl(k->_sa_handler);
546 oact->sa_flags = tswapl(k->sa_flags);
ths388bb212007-05-13 13:58:00 +0000547#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000548 oact->sa_restorer = tswapl(k->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000549#endif
pbrook624f7972008-05-31 16:11:38 +0000550 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000551 }
552 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000553 /* FIXME: This is not threadsafe. */
554 k->_sa_handler = tswapl(act->_sa_handler);
555 k->sa_flags = tswapl(act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000556#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000557 k->sa_restorer = tswapl(act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000558#endif
pbrook624f7972008-05-31 16:11:38 +0000559 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000560
561 /* we update the host linux signal state */
562 host_sig = target_to_host_signal(sig);
563 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
564 sigfillset(&act1.sa_mask);
565 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000566 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000567 act1.sa_flags |= SA_RESTART;
568 /* NOTE: it is important to update the host kernel signal
569 ignore state to avoid getting unexpected interrupted
570 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000571 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000572 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000573 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000574 if (fatal_signal (sig))
575 act1.sa_sigaction = host_signal_handler;
576 else
577 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000578 } else {
579 act1.sa_sigaction = host_signal_handler;
580 }
ths0da46a62007-10-20 20:23:07 +0000581 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000582 }
bellard66fb9762003-03-23 01:06:05 +0000583 }
ths0da46a62007-10-20 20:23:07 +0000584 return ret;
bellard66fb9762003-03-23 01:06:05 +0000585}
bellard31e31b82003-02-18 22:55:36 +0000586
ths5fafdf22007-09-16 21:08:06 +0000587static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
bellard43fff232003-07-09 19:31:39 +0000588 const target_siginfo_t *info)
589{
590 tswap_siginfo(tinfo, info);
591 return 0;
592}
593
thsc3b5bc82007-12-02 06:31:25 +0000594static inline int current_exec_domain_sig(int sig)
595{
596 return /* current->exec_domain && current->exec_domain->signal_invmap
597 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
598}
599
bellard459a4012007-11-11 19:45:10 +0000600#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000601
602/* from the Linux kernel */
603
604struct target_fpreg {
605 uint16_t significand[4];
606 uint16_t exponent;
607};
608
609struct target_fpxreg {
610 uint16_t significand[4];
611 uint16_t exponent;
612 uint16_t padding[3];
613};
614
615struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000616 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000617};
618
619struct target_fpstate {
620 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000621 abi_ulong cw;
622 abi_ulong sw;
623 abi_ulong tag;
624 abi_ulong ipoff;
625 abi_ulong cssel;
626 abi_ulong dataoff;
627 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000628 struct target_fpreg _st[8];
629 uint16_t status;
630 uint16_t magic; /* 0xffff = regular FPU data only */
631
632 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000633 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
634 abi_ulong mxcsr;
635 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000636 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
637 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000638 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000639};
640
641#define X86_FXSR_MAGIC 0x0000
642
643struct target_sigcontext {
644 uint16_t gs, __gsh;
645 uint16_t fs, __fsh;
646 uint16_t es, __esh;
647 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000648 abi_ulong edi;
649 abi_ulong esi;
650 abi_ulong ebp;
651 abi_ulong esp;
652 abi_ulong ebx;
653 abi_ulong edx;
654 abi_ulong ecx;
655 abi_ulong eax;
656 abi_ulong trapno;
657 abi_ulong err;
658 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000659 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000660 abi_ulong eflags;
661 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000662 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000663 abi_ulong fpstate; /* pointer */
664 abi_ulong oldmask;
665 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000666};
667
bellard66fb9762003-03-23 01:06:05 +0000668struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000669 abi_ulong tuc_flags;
670 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +0000671 target_stack_t tuc_stack;
672 struct target_sigcontext tuc_mcontext;
673 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000674};
675
676struct sigframe
677{
blueswir1992f48a2007-10-14 16:27:31 +0000678 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000679 int sig;
680 struct target_sigcontext sc;
681 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000682 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000683 char retcode[8];
684};
685
686struct rt_sigframe
687{
blueswir1992f48a2007-10-14 16:27:31 +0000688 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000689 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000690 abi_ulong pinfo;
691 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000692 struct target_siginfo info;
693 struct target_ucontext uc;
694 struct target_fpstate fpstate;
695 char retcode[8];
696};
697
698/*
699 * Set up a signal frame.
700 */
701
bellard66fb9762003-03-23 01:06:05 +0000702/* XXX: save x87 state */
703static int
704setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000705 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000706{
707 int err = 0;
bellard775b58d2007-11-11 16:22:17 +0000708 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000709
bellard579a97f2007-11-11 14:26:47 +0000710 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000711 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
712 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
713 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
714 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000715 err |= __put_user(env->regs[R_EDI], &sc->edi);
716 err |= __put_user(env->regs[R_ESI], &sc->esi);
717 err |= __put_user(env->regs[R_EBP], &sc->ebp);
718 err |= __put_user(env->regs[R_ESP], &sc->esp);
719 err |= __put_user(env->regs[R_EBX], &sc->ebx);
720 err |= __put_user(env->regs[R_EDX], &sc->edx);
721 err |= __put_user(env->regs[R_ECX], &sc->ecx);
722 err |= __put_user(env->regs[R_EAX], &sc->eax);
bellard66099dd2003-05-08 15:34:02 +0000723 err |= __put_user(env->exception_index, &sc->trapno);
724 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000725 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000726 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000727 err |= __put_user(env->eflags, &sc->eflags);
728 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000729 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000730
bellard28be6232007-11-11 22:23:38 +0000731 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000732 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000733 magic = 0xffff;
734 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000735 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000736
bellard66fb9762003-03-23 01:06:05 +0000737 /* non-iBCS2 extensions.. */
738 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000739 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000740 return err;
741}
742
743/*
744 * Determine which stack to use..
745 */
746
bellard579a97f2007-11-11 14:26:47 +0000747static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000748get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000749{
750 unsigned long esp;
751
752 /* Default to using normal stack */
753 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000754 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000755 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000756 if (sas_ss_flags(esp) == 0)
757 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
758 }
bellard66fb9762003-03-23 01:06:05 +0000759
760 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000761 else
bellarda52c7572003-06-21 13:14:12 +0000762 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000763 !(ka->sa_flags & TARGET_SA_RESTORER) &&
764 ka->sa_restorer) {
765 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000766 }
bellard579a97f2007-11-11 14:26:47 +0000767 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000768}
769
bellard579a97f2007-11-11 14:26:47 +0000770/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000771static void setup_frame(int sig, struct target_sigaction *ka,
bellard66fb9762003-03-23 01:06:05 +0000772 target_sigset_t *set, CPUX86State *env)
773{
bellard579a97f2007-11-11 14:26:47 +0000774 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000775 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000776 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000777
bellard579a97f2007-11-11 14:26:47 +0000778 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000779
bellard579a97f2007-11-11 14:26:47 +0000780 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000781 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000782
thsc3b5bc82007-12-02 06:31:25 +0000783 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000784 &frame->sig);
785 if (err)
786 goto give_sigsegv;
787
bellard28be6232007-11-11 22:23:38 +0000788 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
789 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000790 if (err)
791 goto give_sigsegv;
792
bellard92319442004-06-19 16:58:13 +0000793 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
794 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
795 goto give_sigsegv;
796 }
bellard66fb9762003-03-23 01:06:05 +0000797
798 /* Set up to return from userspace. If provided, use a stub
799 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000800 if (ka->sa_flags & TARGET_SA_RESTORER) {
801 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000802 } else {
bellard775b58d2007-11-11 16:22:17 +0000803 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000804 abi_ulong retcode_addr;
805 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
806 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000807 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000808 val16 = 0xb858;
809 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000810 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000811 val16 = 0x80cd;
812 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000813 }
814
815 if (err)
816 goto give_sigsegv;
817
818 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000819 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000820 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000821
822 cpu_x86_load_seg(env, R_DS, __USER_DS);
823 cpu_x86_load_seg(env, R_ES, __USER_DS);
824 cpu_x86_load_seg(env, R_SS, __USER_DS);
825 cpu_x86_load_seg(env, R_CS, __USER_CS);
826 env->eflags &= ~TF_MASK;
827
bellard579a97f2007-11-11 14:26:47 +0000828 unlock_user_struct(frame, frame_addr, 1);
829
bellard66fb9762003-03-23 01:06:05 +0000830 return;
831
832give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000833 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000834 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000835 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000836 force_sig(TARGET_SIGSEGV /* , current */);
837}
838
bellard579a97f2007-11-11 14:26:47 +0000839/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000840static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard9de5e442003-03-23 16:49:39 +0000841 target_siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +0000842 target_sigset_t *set, CPUX86State *env)
843{
bellard28be6232007-11-11 22:23:38 +0000844 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000845 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000846 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000847
bellard579a97f2007-11-11 14:26:47 +0000848 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000849
bellard579a97f2007-11-11 14:26:47 +0000850 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000851 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000852
thsc3b5bc82007-12-02 06:31:25 +0000853 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000854 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000855 addr = frame_addr + offsetof(struct rt_sigframe, info);
856 err |= __put_user(addr, &frame->pinfo);
857 addr = frame_addr + offsetof(struct rt_sigframe, uc);
858 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000859 err |= copy_siginfo_to_user(&frame->info, info);
860 if (err)
861 goto give_sigsegv;
862
863 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000864 err |= __put_user(0, &frame->uc.tuc_flags);
865 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000866 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000867 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000868 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000869 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000870 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000871 &frame->uc.tuc_stack.ss_size);
872 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000873 env, set->sig[0],
874 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000875 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000876 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000877 goto give_sigsegv;
878 }
bellard66fb9762003-03-23 01:06:05 +0000879
880 /* Set up to return from userspace. If provided, use a stub
881 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000882 if (ka->sa_flags & TARGET_SA_RESTORER) {
883 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000884 } else {
bellard775b58d2007-11-11 16:22:17 +0000885 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000886 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
887 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000888 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000889 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000890 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000891 val16 = 0x80cd;
892 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000893 }
894
895 if (err)
896 goto give_sigsegv;
897
898 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000899 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000900 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000901
902 cpu_x86_load_seg(env, R_DS, __USER_DS);
903 cpu_x86_load_seg(env, R_ES, __USER_DS);
904 cpu_x86_load_seg(env, R_SS, __USER_DS);
905 cpu_x86_load_seg(env, R_CS, __USER_CS);
906 env->eflags &= ~TF_MASK;
907
bellard579a97f2007-11-11 14:26:47 +0000908 unlock_user_struct(frame, frame_addr, 1);
909
bellard66fb9762003-03-23 01:06:05 +0000910 return;
911
912give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000913 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000914 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000915 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000916 force_sig(TARGET_SIGSEGV /* , current */);
917}
918
919static int
920restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
921{
922 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000923 abi_ulong fpstate_addr;
924 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000925
bellard28be6232007-11-11 22:23:38 +0000926 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
927 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
928 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
929 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +0000930
bellard28be6232007-11-11 22:23:38 +0000931 env->regs[R_EDI] = tswapl(sc->edi);
932 env->regs[R_ESI] = tswapl(sc->esi);
933 env->regs[R_EBP] = tswapl(sc->ebp);
934 env->regs[R_ESP] = tswapl(sc->esp);
935 env->regs[R_EBX] = tswapl(sc->ebx);
936 env->regs[R_EDX] = tswapl(sc->edx);
937 env->regs[R_ECX] = tswapl(sc->ecx);
938 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +0000939
940 cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
941 cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +0000942
bellard28be6232007-11-11 22:23:38 +0000943 tmpflags = tswapl(sc->eflags);
944 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
945 // regs->orig_eax = -1; /* disable syscall checks */
946
947 fpstate_addr = tswapl(sc->fpstate);
948 if (fpstate_addr != 0) {
949 if (!access_ok(VERIFY_READ, fpstate_addr,
950 sizeof(struct target_fpstate)))
951 goto badframe;
952 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000953 }
954
bellard28be6232007-11-11 22:23:38 +0000955 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +0000956 return err;
bellard66fb9762003-03-23 01:06:05 +0000957badframe:
958 return 1;
bellard66fb9762003-03-23 01:06:05 +0000959}
960
961long do_sigreturn(CPUX86State *env)
962{
bellard579a97f2007-11-11 14:26:47 +0000963 struct sigframe *frame;
964 abi_ulong frame_addr = env->regs[R_ESP] - 8;
bellard66fb9762003-03-23 01:06:05 +0000965 target_sigset_t target_set;
966 sigset_t set;
967 int eax, i;
968
bellard447db212003-05-10 15:10:36 +0000969#if defined(DEBUG_SIGNAL)
970 fprintf(stderr, "do_sigreturn\n");
971#endif
bellard579a97f2007-11-11 14:26:47 +0000972 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
973 goto badframe;
bellard66fb9762003-03-23 01:06:05 +0000974 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +0000975 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
976 goto badframe;
977 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
978 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
979 goto badframe;
980 }
bellard66fb9762003-03-23 01:06:05 +0000981
bellard92319442004-06-19 16:58:13 +0000982 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +0000983 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +0000984
bellard66fb9762003-03-23 01:06:05 +0000985 /* restore registers */
986 if (restore_sigcontext(env, &frame->sc, &eax))
987 goto badframe;
bellard579a97f2007-11-11 14:26:47 +0000988 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +0000989 return eax;
990
991badframe:
bellard579a97f2007-11-11 14:26:47 +0000992 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +0000993 force_sig(TARGET_SIGSEGV);
994 return 0;
995}
996
997long do_rt_sigreturn(CPUX86State *env)
998{
bellard28be6232007-11-11 22:23:38 +0000999 abi_ulong frame_addr;
1000 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001001 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001002 int eax;
1003
bellard28be6232007-11-11 22:23:38 +00001004 frame_addr = env->regs[R_ESP] - 4;
1005 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1006 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001007 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +00001008 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001009
bellardb8076a72005-04-07 22:20:31 +00001010 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001011 goto badframe;
1012
bellard28be6232007-11-11 22:23:38 +00001013 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1014 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001015 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001016
bellard28be6232007-11-11 22:23:38 +00001017 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001018 return eax;
1019
1020badframe:
bellard28be6232007-11-11 22:23:38 +00001021 unlock_user_struct(frame, frame_addr, 0);
1022 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001023 return 0;
1024}
1025
bellard43fff232003-07-09 19:31:39 +00001026#elif defined(TARGET_ARM)
1027
1028struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001029 abi_ulong trap_no;
1030 abi_ulong error_code;
1031 abi_ulong oldmask;
1032 abi_ulong arm_r0;
1033 abi_ulong arm_r1;
1034 abi_ulong arm_r2;
1035 abi_ulong arm_r3;
1036 abi_ulong arm_r4;
1037 abi_ulong arm_r5;
1038 abi_ulong arm_r6;
1039 abi_ulong arm_r7;
1040 abi_ulong arm_r8;
1041 abi_ulong arm_r9;
1042 abi_ulong arm_r10;
1043 abi_ulong arm_fp;
1044 abi_ulong arm_ip;
1045 abi_ulong arm_sp;
1046 abi_ulong arm_lr;
1047 abi_ulong arm_pc;
1048 abi_ulong arm_cpsr;
1049 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001050};
1051
pbrooka745ec62008-05-06 15:36:17 +00001052struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001053 abi_ulong tuc_flags;
1054 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +00001055 target_stack_t tuc_stack;
1056 struct target_sigcontext tuc_mcontext;
1057 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001058};
1059
pbrooka745ec62008-05-06 15:36:17 +00001060struct target_ucontext_v2 {
1061 abi_ulong tuc_flags;
1062 abi_ulong tuc_link;
1063 target_stack_t tuc_stack;
1064 struct target_sigcontext tuc_mcontext;
1065 target_sigset_t tuc_sigmask; /* mask last for extensibility */
1066 char __unused[128 - sizeof(sigset_t)];
1067 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1068};
1069
pbrooka8c33202008-05-07 23:22:46 +00001070struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001071{
1072 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001073 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1074 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001075};
1076
pbrooka8c33202008-05-07 23:22:46 +00001077struct sigframe_v2
1078{
1079 struct target_ucontext_v2 uc;
1080 abi_ulong retcode;
1081};
1082
pbrooka745ec62008-05-06 15:36:17 +00001083struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001084{
bellardf8b0aa22007-11-11 23:03:42 +00001085 abi_ulong pinfo;
1086 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001087 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001088 struct target_ucontext_v1 uc;
1089 abi_ulong retcode;
1090};
1091
1092struct rt_sigframe_v2
1093{
1094 struct target_siginfo info;
1095 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001096 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001097};
1098
1099#define TARGET_CONFIG_CPU_32 1
1100
1101/*
1102 * For ARM syscalls, we encode the syscall number into the instruction.
1103 */
1104#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1105#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1106
1107/*
1108 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1109 * need two 16-bit instructions.
1110 */
1111#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1112#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1113
blueswir1992f48a2007-10-14 16:27:31 +00001114static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001115 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1116 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1117};
1118
1119
bellard43fff232003-07-09 19:31:39 +00001120#define __get_user_error(x,p,e) __get_user(x, p)
1121
1122static inline int valid_user_regs(CPUState *regs)
1123{
1124 return 1;
1125}
1126
pbrooka8c33202008-05-07 23:22:46 +00001127static void
bellard43fff232003-07-09 19:31:39 +00001128setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
bellardf8b0aa22007-11-11 23:03:42 +00001129 CPUState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001130{
pbrooka8c33202008-05-07 23:22:46 +00001131 __put_user(env->regs[0], &sc->arm_r0);
1132 __put_user(env->regs[1], &sc->arm_r1);
1133 __put_user(env->regs[2], &sc->arm_r2);
1134 __put_user(env->regs[3], &sc->arm_r3);
1135 __put_user(env->regs[4], &sc->arm_r4);
1136 __put_user(env->regs[5], &sc->arm_r5);
1137 __put_user(env->regs[6], &sc->arm_r6);
1138 __put_user(env->regs[7], &sc->arm_r7);
1139 __put_user(env->regs[8], &sc->arm_r8);
1140 __put_user(env->regs[9], &sc->arm_r9);
1141 __put_user(env->regs[10], &sc->arm_r10);
1142 __put_user(env->regs[11], &sc->arm_fp);
1143 __put_user(env->regs[12], &sc->arm_ip);
1144 __put_user(env->regs[13], &sc->arm_sp);
1145 __put_user(env->regs[14], &sc->arm_lr);
1146 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001147#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001148 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001149#endif
1150
pbrooka8c33202008-05-07 23:22:46 +00001151 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1152 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1153 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1154 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001155}
1156
bellard579a97f2007-11-11 14:26:47 +00001157static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00001158get_sigframe(struct target_sigaction *ka, CPUState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001159{
1160 unsigned long sp = regs->regs[13];
1161
bellard43fff232003-07-09 19:31:39 +00001162 /*
1163 * This is the X/Open sanctioned signal stack switching.
1164 */
pbrook624f7972008-05-31 16:11:38 +00001165 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001166 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001167 /*
1168 * ATPCS B01 mandates 8-byte alignment
1169 */
bellard579a97f2007-11-11 14:26:47 +00001170 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001171}
1172
1173static int
pbrook624f7972008-05-31 16:11:38 +00001174setup_return(CPUState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001175 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001176{
pbrook624f7972008-05-31 16:11:38 +00001177 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001178 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001179 int thumb = handler & 1;
bellard43fff232003-07-09 19:31:39 +00001180
pbrook624f7972008-05-31 16:11:38 +00001181 if (ka->sa_flags & TARGET_SA_RESTORER) {
1182 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001183 } else {
1184 unsigned int idx = thumb;
1185
pbrook624f7972008-05-31 16:11:38 +00001186 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001187 idx += 2;
1188
1189 if (__put_user(retcodes[idx], rc))
1190 return 1;
1191#if 0
blueswir1992f48a2007-10-14 16:27:31 +00001192 flush_icache_range((abi_ulong)rc,
1193 (abi_ulong)(rc + 1));
bellard43fff232003-07-09 19:31:39 +00001194#endif
bellardf8b0aa22007-11-11 23:03:42 +00001195 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001196 }
1197
1198 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001199 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001200 env->regs[14] = retcode;
1201 env->regs[15] = handler & (thumb ? ~1 : ~3);
pbrook75b680e2008-03-21 16:07:30 +00001202 env->thumb = thumb;
bellard43fff232003-07-09 19:31:39 +00001203
bellardb5ff1b32005-11-26 10:38:39 +00001204#if 0
bellard43fff232003-07-09 19:31:39 +00001205#ifdef TARGET_CONFIG_CPU_32
1206 env->cpsr = cpsr;
1207#endif
bellardb5ff1b32005-11-26 10:38:39 +00001208#endif
bellard43fff232003-07-09 19:31:39 +00001209
1210 return 0;
1211}
1212
pbrooka8c33202008-05-07 23:22:46 +00001213static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
1214 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001215{
pbrooka8c33202008-05-07 23:22:46 +00001216 struct target_sigaltstack stack;
1217 int i;
1218
1219 /* Clear all the bits of the ucontext we don't use. */
1220 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1221
1222 memset(&stack, 0, sizeof(stack));
1223 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1224 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1225 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1226 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1227
1228 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
1229 /* FIXME: Save coprocessor signal frame. */
1230 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1231 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1232 }
1233}
1234
1235/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001236static void setup_frame_v1(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001237 target_sigset_t *set, CPUState *regs)
1238{
1239 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001240 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001241 int i;
bellard43fff232003-07-09 19:31:39 +00001242
bellard579a97f2007-11-11 14:26:47 +00001243 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1244 return;
1245
pbrooka8c33202008-05-07 23:22:46 +00001246 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001247
bellard92319442004-06-19 16:58:13 +00001248 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1249 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001250 goto end;
bellard43fff232003-07-09 19:31:39 +00001251 }
1252
pbrooka8c33202008-05-07 23:22:46 +00001253 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1254 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001255
1256end:
1257 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001258}
1259
pbrook624f7972008-05-31 16:11:38 +00001260static void setup_frame_v2(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001261 target_sigset_t *set, CPUState *regs)
1262{
1263 struct sigframe_v2 *frame;
1264 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1265
1266 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1267 return;
1268
1269 setup_sigframe_v2(&frame->uc, set, regs);
1270
1271 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1272 frame_addr + offsetof(struct sigframe_v2, retcode));
1273
1274 unlock_user_struct(frame, frame_addr, 1);
1275}
1276
pbrook624f7972008-05-31 16:11:38 +00001277static void setup_frame(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001278 target_sigset_t *set, CPUState *regs)
1279{
1280 if (get_osversion() >= 0x020612) {
1281 setup_frame_v2(usig, ka, set, regs);
1282 } else {
1283 setup_frame_v1(usig, ka, set, regs);
1284 }
bellard43fff232003-07-09 19:31:39 +00001285}
1286
bellard579a97f2007-11-11 14:26:47 +00001287/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001288static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001289 target_siginfo_t *info,
1290 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001291{
pbrooka745ec62008-05-06 15:36:17 +00001292 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001293 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001294 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001295 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001296 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001297
bellard579a97f2007-11-11 14:26:47 +00001298 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001299 return /* 1 */;
1300
pbrooka745ec62008-05-06 15:36:17 +00001301 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001302 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001303 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001304 __put_user(uc_addr, &frame->puc);
1305 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001306
1307 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001308 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001309
thsa04e1342007-09-27 13:57:58 +00001310 memset(&stack, 0, sizeof(stack));
1311 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1312 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1313 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001314 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001315
pbrooka8c33202008-05-07 23:22:46 +00001316 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001317 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001318 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001319 goto end;
bellard92319442004-06-19 16:58:13 +00001320 }
bellard43fff232003-07-09 19:31:39 +00001321
pbrooka8c33202008-05-07 23:22:46 +00001322 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1323 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001324
pbrooka8c33202008-05-07 23:22:46 +00001325 env->regs[1] = info_addr;
1326 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001327
1328end:
1329 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001330}
1331
pbrook624f7972008-05-31 16:11:38 +00001332static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001333 target_siginfo_t *info,
1334 target_sigset_t *set, CPUState *env)
1335{
1336 struct rt_sigframe_v2 *frame;
1337 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001338 abi_ulong info_addr, uc_addr;
1339
1340 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1341 return /* 1 */;
1342
1343 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1344 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001345 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001346
pbrooka8c33202008-05-07 23:22:46 +00001347 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001348
pbrooka8c33202008-05-07 23:22:46 +00001349 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1350 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001351
pbrooka8c33202008-05-07 23:22:46 +00001352 env->regs[1] = info_addr;
1353 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001354
bellard579a97f2007-11-11 14:26:47 +00001355 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001356}
1357
pbrook624f7972008-05-31 16:11:38 +00001358static void setup_rt_frame(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001359 target_siginfo_t *info,
1360 target_sigset_t *set, CPUState *env)
1361{
1362 if (get_osversion() >= 0x020612) {
1363 setup_rt_frame_v2(usig, ka, info, set, env);
1364 } else {
1365 setup_rt_frame_v1(usig, ka, info, set, env);
1366 }
1367}
1368
bellard43fff232003-07-09 19:31:39 +00001369static int
1370restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
1371{
1372 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001373 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001374
1375 __get_user_error(env->regs[0], &sc->arm_r0, err);
1376 __get_user_error(env->regs[1], &sc->arm_r1, err);
1377 __get_user_error(env->regs[2], &sc->arm_r2, err);
1378 __get_user_error(env->regs[3], &sc->arm_r3, err);
1379 __get_user_error(env->regs[4], &sc->arm_r4, err);
1380 __get_user_error(env->regs[5], &sc->arm_r5, err);
1381 __get_user_error(env->regs[6], &sc->arm_r6, err);
1382 __get_user_error(env->regs[7], &sc->arm_r7, err);
1383 __get_user_error(env->regs[8], &sc->arm_r8, err);
1384 __get_user_error(env->regs[9], &sc->arm_r9, err);
1385 __get_user_error(env->regs[10], &sc->arm_r10, err);
1386 __get_user_error(env->regs[11], &sc->arm_fp, err);
1387 __get_user_error(env->regs[12], &sc->arm_ip, err);
1388 __get_user_error(env->regs[13], &sc->arm_sp, err);
1389 __get_user_error(env->regs[14], &sc->arm_lr, err);
1390 __get_user_error(env->regs[15], &sc->arm_pc, err);
1391#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001392 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001393 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001394#endif
1395
1396 err |= !valid_user_regs(env);
1397
1398 return err;
1399}
1400
pbrooka8c33202008-05-07 23:22:46 +00001401long do_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001402{
bellardf8b0aa22007-11-11 23:03:42 +00001403 abi_ulong frame_addr;
pbrooka8c33202008-05-07 23:22:46 +00001404 struct sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001405 target_sigset_t set;
1406 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001407 int i;
bellard43fff232003-07-09 19:31:39 +00001408
1409 /*
1410 * Since we stacked the signal on a 64-bit boundary,
1411 * then 'sp' should be word aligned here. If it's
1412 * not, then the user is trying to mess with us.
1413 */
1414 if (env->regs[13] & 7)
1415 goto badframe;
1416
bellardf8b0aa22007-11-11 23:03:42 +00001417 frame_addr = env->regs[13];
1418 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1419 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001420
bellard92319442004-06-19 16:58:13 +00001421 if (__get_user(set.sig[0], &frame->sc.oldmask))
1422 goto badframe;
1423 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1424 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1425 goto badframe;
1426 }
bellard43fff232003-07-09 19:31:39 +00001427
bellard92319442004-06-19 16:58:13 +00001428 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001429 sigprocmask(SIG_SETMASK, &host_set, NULL);
1430
1431 if (restore_sigcontext(env, &frame->sc))
1432 goto badframe;
1433
1434#if 0
1435 /* Send SIGTRAP if we're single-stepping */
1436 if (ptrace_cancel_bpt(current))
1437 send_sig(SIGTRAP, current, 1);
1438#endif
bellardf8b0aa22007-11-11 23:03:42 +00001439 unlock_user_struct(frame, frame_addr, 0);
1440 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001441
1442badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001443 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001444 force_sig(SIGSEGV /* , current */);
1445 return 0;
1446}
1447
pbrooka8c33202008-05-07 23:22:46 +00001448static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr,
1449 struct target_ucontext_v2 *uc)
1450{
1451 sigset_t host_set;
1452
1453 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1454 sigprocmask(SIG_SETMASK, &host_set, NULL);
1455
1456 if (restore_sigcontext(env, &uc->tuc_mcontext))
1457 return 1;
1458
1459 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1460 return 1;
1461
1462#if 0
1463 /* Send SIGTRAP if we're single-stepping */
1464 if (ptrace_cancel_bpt(current))
1465 send_sig(SIGTRAP, current, 1);
1466#endif
1467
1468 return 0;
1469}
1470
1471long do_sigreturn_v2(CPUState *env)
1472{
1473 abi_ulong frame_addr;
1474 struct sigframe_v2 *frame;
1475
1476 /*
1477 * Since we stacked the signal on a 64-bit boundary,
1478 * then 'sp' should be word aligned here. If it's
1479 * not, then the user is trying to mess with us.
1480 */
1481 if (env->regs[13] & 7)
1482 goto badframe;
1483
1484 frame_addr = env->regs[13];
1485 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1486 goto badframe;
1487
1488 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1489 goto badframe;
1490
1491 unlock_user_struct(frame, frame_addr, 0);
1492 return env->regs[0];
1493
1494badframe:
1495 unlock_user_struct(frame, frame_addr, 0);
1496 force_sig(SIGSEGV /* , current */);
1497 return 0;
1498}
1499
1500long do_sigreturn(CPUState *env)
1501{
1502 if (get_osversion() >= 0x020612) {
1503 return do_sigreturn_v2(env);
1504 } else {
1505 return do_sigreturn_v1(env);
1506 }
1507}
1508
pbrooka745ec62008-05-06 15:36:17 +00001509long do_rt_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001510{
bellardf8b0aa22007-11-11 23:03:42 +00001511 abi_ulong frame_addr;
pbrooka745ec62008-05-06 15:36:17 +00001512 struct rt_sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001513 sigset_t host_set;
1514
1515 /*
1516 * Since we stacked the signal on a 64-bit boundary,
1517 * then 'sp' should be word aligned here. If it's
1518 * not, then the user is trying to mess with us.
1519 */
1520 if (env->regs[13] & 7)
1521 goto badframe;
1522
bellardf8b0aa22007-11-11 23:03:42 +00001523 frame_addr = env->regs[13];
1524 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1525 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001526
bellardb8076a72005-04-07 22:20:31 +00001527 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00001528 sigprocmask(SIG_SETMASK, &host_set, NULL);
1529
bellardb8076a72005-04-07 22:20:31 +00001530 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00001531 goto badframe;
1532
pbrooka745ec62008-05-06 15:36:17 +00001533 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 +00001534 goto badframe;
1535
bellard43fff232003-07-09 19:31:39 +00001536#if 0
1537 /* Send SIGTRAP if we're single-stepping */
1538 if (ptrace_cancel_bpt(current))
1539 send_sig(SIGTRAP, current, 1);
1540#endif
bellardf8b0aa22007-11-11 23:03:42 +00001541 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001542 return env->regs[0];
1543
1544badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001545 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001546 force_sig(SIGSEGV /* , current */);
1547 return 0;
1548}
1549
pbrooka745ec62008-05-06 15:36:17 +00001550long do_rt_sigreturn_v2(CPUState *env)
1551{
1552 abi_ulong frame_addr;
1553 struct rt_sigframe_v2 *frame;
pbrooka745ec62008-05-06 15:36:17 +00001554
1555 /*
1556 * Since we stacked the signal on a 64-bit boundary,
1557 * then 'sp' should be word aligned here. If it's
1558 * not, then the user is trying to mess with us.
1559 */
1560 if (env->regs[13] & 7)
1561 goto badframe;
1562
1563 frame_addr = env->regs[13];
1564 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1565 goto badframe;
1566
pbrooka8c33202008-05-07 23:22:46 +00001567 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1568 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00001569
pbrooka745ec62008-05-06 15:36:17 +00001570 unlock_user_struct(frame, frame_addr, 0);
1571 return env->regs[0];
1572
1573badframe:
1574 unlock_user_struct(frame, frame_addr, 0);
1575 force_sig(SIGSEGV /* , current */);
1576 return 0;
1577}
1578
1579long do_rt_sigreturn(CPUState *env)
1580{
1581 if (get_osversion() >= 0x020612) {
1582 return do_rt_sigreturn_v2(env);
1583 } else {
1584 return do_rt_sigreturn_v1(env);
1585 }
1586}
1587
bellard6d5e2162004-09-30 22:04:13 +00001588#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00001589
bellard6d5e2162004-09-30 22:04:13 +00001590#define __SUNOS_MAXWIN 31
1591
1592/* This is what SunOS does, so shall I. */
1593struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001594 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00001595
blueswir1992f48a2007-10-14 16:27:31 +00001596 abi_ulong sigc_mask; /* sigmask to restore */
1597 abi_ulong sigc_sp; /* stack pointer */
1598 abi_ulong sigc_pc; /* program counter */
1599 abi_ulong sigc_npc; /* next program counter */
1600 abi_ulong sigc_psr; /* for condition codes etc */
1601 abi_ulong sigc_g1; /* User uses these two registers */
1602 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00001603
1604 /* Now comes information regarding the users window set
1605 * at the time of the signal.
1606 */
blueswir1992f48a2007-10-14 16:27:31 +00001607 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00001608
1609 /* stack ptrs for each regwin buf */
1610 char *sigc_spbuf[__SUNOS_MAXWIN];
1611
1612 /* Windows to restore after signal */
1613 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001614 abi_ulong locals[8];
1615 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00001616 } sigc_wbuf[__SUNOS_MAXWIN];
1617};
1618/* A Sparc stack frame */
1619struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00001620 abi_ulong locals[8];
1621 abi_ulong ins[6];
bellard6d5e2162004-09-30 22:04:13 +00001622 struct sparc_stackf *fp;
blueswir1992f48a2007-10-14 16:27:31 +00001623 abi_ulong callers_pc;
bellard6d5e2162004-09-30 22:04:13 +00001624 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00001625 abi_ulong xargs[6];
1626 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00001627};
1628
1629typedef struct {
1630 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001631 abi_ulong psr;
1632 abi_ulong pc;
1633 abi_ulong npc;
1634 abi_ulong y;
1635 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00001636 } si_regs;
1637 int si_mask;
1638} __siginfo_t;
1639
1640typedef struct {
1641 unsigned long si_float_regs [32];
1642 unsigned long si_fsr;
1643 unsigned long si_fpqdepth;
1644 struct {
1645 unsigned long *insn_addr;
1646 unsigned long insn;
1647 } si_fpqueue [16];
bellard74ccb342006-07-18 21:23:34 +00001648} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00001649
1650
1651struct target_signal_frame {
1652 struct sparc_stackf ss;
1653 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00001654 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00001655 abi_ulong insns[2] __attribute__ ((aligned (8)));
1656 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
1657 abi_ulong extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001658 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001659};
1660struct target_rt_signal_frame {
1661 struct sparc_stackf ss;
1662 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00001663 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00001664 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00001665 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00001666 unsigned int insns[2];
1667 stack_t stack;
1668 unsigned int extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001669 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001670};
1671
bellarde80cfcf2004-12-19 23:18:01 +00001672#define UREG_O0 16
1673#define UREG_O6 22
1674#define UREG_I0 0
1675#define UREG_I1 1
1676#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00001677#define UREG_I3 3
1678#define UREG_I4 4
1679#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00001680#define UREG_I6 6
1681#define UREG_I7 7
1682#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00001683#define UREG_FP UREG_I6
1684#define UREG_SP UREG_O6
1685
pbrook624f7972008-05-31 16:11:38 +00001686static inline abi_ulong get_sigframe(struct target_sigaction *sa,
bellard459a4012007-11-11 19:45:10 +00001687 CPUState *env, unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00001688{
bellard459a4012007-11-11 19:45:10 +00001689 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00001690
1691 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00001692
1693 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00001694 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00001695 if (!on_sig_stack(sp)
1696 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
1697 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00001698 }
bellard459a4012007-11-11 19:45:10 +00001699 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00001700}
1701
1702static int
blueswir1992f48a2007-10-14 16:27:31 +00001703setup___siginfo(__siginfo_t *si, CPUState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00001704{
1705 int err = 0, i;
1706
bellard6d5e2162004-09-30 22:04:13 +00001707 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00001708 err |= __put_user(env->pc, &si->si_regs.pc);
1709 err |= __put_user(env->npc, &si->si_regs.npc);
1710 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001711 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00001712 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
1713 }
bellarda315a142005-01-30 22:59:18 +00001714 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001715 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00001716 }
bellard6d5e2162004-09-30 22:04:13 +00001717 err |= __put_user(mask, &si->si_mask);
1718 return err;
1719}
bellarde80cfcf2004-12-19 23:18:01 +00001720
bellard80a9d032005-01-03 23:31:27 +00001721#if 0
bellard6d5e2162004-09-30 22:04:13 +00001722static int
1723setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
1724 CPUState *env, unsigned long mask)
1725{
1726 int err = 0;
1727
1728 err |= __put_user(mask, &sc->sigc_mask);
1729 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
1730 err |= __put_user(env->pc, &sc->sigc_pc);
1731 err |= __put_user(env->npc, &sc->sigc_npc);
1732 err |= __put_user(env->psr, &sc->sigc_psr);
1733 err |= __put_user(env->gregs[1], &sc->sigc_g1);
1734 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
1735
1736 return err;
1737}
bellard80a9d032005-01-03 23:31:27 +00001738#endif
bellard6d5e2162004-09-30 22:04:13 +00001739#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
1740
pbrook624f7972008-05-31 16:11:38 +00001741static void setup_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001742 target_sigset_t *set, CPUState *env)
1743{
bellard459a4012007-11-11 19:45:10 +00001744 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001745 struct target_signal_frame *sf;
1746 int sigframe_size, err, i;
1747
1748 /* 1. Make sure everything is clean */
1749 //synchronize_user_stack();
1750
1751 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00001752 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00001753
bellard459a4012007-11-11 19:45:10 +00001754 sf = lock_user(VERIFY_WRITE, sf_addr,
1755 sizeof(struct target_signal_frame), 0);
1756 if (!sf)
1757 goto sigsegv;
1758
bellarde80cfcf2004-12-19 23:18:01 +00001759 //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 +00001760#if 0
1761 if (invalid_frame_pointer(sf, sigframe_size))
1762 goto sigill_and_return;
1763#endif
1764 /* 2. Save the current process state */
1765 err = setup___siginfo(&sf->info, env, set->sig[0]);
1766 err |= __put_user(0, &sf->extra_size);
1767
1768 //err |= save_fpu_state(regs, &sf->fpu_state);
1769 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
1770
1771 err |= __put_user(set->sig[0], &sf->info.si_mask);
1772 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
1773 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
1774 }
1775
bellarda315a142005-01-30 22:59:18 +00001776 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001777 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00001778 }
bellarda315a142005-01-30 22:59:18 +00001779 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001780 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00001781 }
bellard6d5e2162004-09-30 22:04:13 +00001782 if (err)
1783 goto sigsegv;
1784
1785 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00001786 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001787 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00001788 env->regwptr[UREG_I1] = sf_addr +
1789 offsetof(struct target_signal_frame, info);
1790 env->regwptr[UREG_I2] = sf_addr +
1791 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00001792
1793 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00001794 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00001795 env->npc = (env->pc + 4);
1796 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00001797 if (ka->sa_restorer)
1798 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00001799 else {
bellard775b58d2007-11-11 16:22:17 +00001800 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00001801
1802 env->regwptr[UREG_I7] = sf_addr +
1803 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00001804
1805 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00001806 val32 = 0x821020d8;
1807 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00001808
1809 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00001810 val32 = 0x91d02010;
1811 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00001812 if (err)
1813 goto sigsegv;
1814
1815 /* Flush instruction space. */
1816 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00001817 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00001818 }
bellard459a4012007-11-11 19:45:10 +00001819 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001820 return;
bellard459a4012007-11-11 19:45:10 +00001821#if 0
1822sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00001823 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00001824#endif
bellard6d5e2162004-09-30 22:04:13 +00001825sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00001826 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00001827 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001828 force_sig(TARGET_SIGSEGV);
1829}
1830static inline int
bellard74ccb342006-07-18 21:23:34 +00001831restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00001832{
1833 int err;
1834#if 0
1835#ifdef CONFIG_SMP
1836 if (current->flags & PF_USEDFPU)
1837 regs->psr &= ~PSR_EF;
1838#else
1839 if (current == last_task_used_math) {
1840 last_task_used_math = 0;
1841 regs->psr &= ~PSR_EF;
1842 }
1843#endif
1844 current->used_math = 1;
1845 current->flags &= ~PF_USEDFPU;
1846#endif
1847#if 0
1848 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
1849 return -EFAULT;
1850#endif
1851
bellardfafffae2006-10-28 12:09:16 +00001852#if 0
1853 /* XXX: incorrect */
bellard6d5e2162004-09-30 22:04:13 +00001854 err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
1855 (sizeof(unsigned long) * 32));
bellardfafffae2006-10-28 12:09:16 +00001856#endif
bellard6d5e2162004-09-30 22:04:13 +00001857 err |= __get_user(env->fsr, &fpu->si_fsr);
1858#if 0
1859 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
1860 if (current->thread.fpqdepth != 0)
1861 err |= __copy_from_user(&current->thread.fpqueue[0],
1862 &fpu->si_fpqueue[0],
1863 ((sizeof(unsigned long) +
1864 (sizeof(unsigned long *)))*16));
1865#endif
1866 return err;
1867}
1868
1869
pbrook624f7972008-05-31 16:11:38 +00001870static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001871 target_siginfo_t *info,
1872 target_sigset_t *set, CPUState *env)
1873{
1874 fprintf(stderr, "setup_rt_frame: not implemented\n");
1875}
1876
1877long do_sigreturn(CPUState *env)
1878{
bellardf8b0aa22007-11-11 23:03:42 +00001879 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001880 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00001881 uint32_t up_psr, pc, npc;
bellard6d5e2162004-09-30 22:04:13 +00001882 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00001883 sigset_t host_set;
bellardf8b0aa22007-11-11 23:03:42 +00001884 abi_ulong fpu_save_addr;
bellarde80cfcf2004-12-19 23:18:01 +00001885 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00001886
bellardf8b0aa22007-11-11 23:03:42 +00001887 sf_addr = env->regwptr[UREG_FP];
1888 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
1889 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00001890#if 0
bellarde80cfcf2004-12-19 23:18:01 +00001891 fprintf(stderr, "sigreturn\n");
1892 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 +00001893#endif
bellarde80cfcf2004-12-19 23:18:01 +00001894 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00001895
1896 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00001897
bellardf8b0aa22007-11-11 23:03:42 +00001898 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00001899 goto segv_and_exit;
1900
1901 err = __get_user(pc, &sf->info.si_regs.pc);
1902 err |= __get_user(npc, &sf->info.si_regs.npc);
1903
bellard6d5e2162004-09-30 22:04:13 +00001904 if ((pc | npc) & 3)
1905 goto segv_and_exit;
1906
1907 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00001908 err |= __get_user(up_psr, &sf->info.si_regs.psr);
1909
bellard6d5e2162004-09-30 22:04:13 +00001910 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00001911 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
1912 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
1913
1914 env->pc = pc;
1915 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00001916 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001917 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001918 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
1919 }
bellarda315a142005-01-30 22:59:18 +00001920 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001921 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
1922 }
bellard6d5e2162004-09-30 22:04:13 +00001923
bellardf8b0aa22007-11-11 23:03:42 +00001924 err |= __get_user(fpu_save_addr, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001925
bellarde80cfcf2004-12-19 23:18:01 +00001926 //if (fpu_save)
1927 // err |= restore_fpu_state(env, fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001928
1929 /* This is pretty much atomic, no amount locking would prevent
1930 * the races which exist anyways.
1931 */
1932 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00001933 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1934 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
1935 }
1936
1937 target_to_host_sigset_internal(&host_set, &set);
1938 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00001939
1940 if (err)
1941 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00001942 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001943 return env->regwptr[0];
1944
1945segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00001946 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001947 force_sig(TARGET_SIGSEGV);
1948}
1949
1950long do_rt_sigreturn(CPUState *env)
1951{
1952 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00001953 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00001954}
1955
bellard459a4012007-11-11 19:45:10 +00001956#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00001957#define MC_TSTATE 0
1958#define MC_PC 1
1959#define MC_NPC 2
1960#define MC_Y 3
1961#define MC_G1 4
1962#define MC_G2 5
1963#define MC_G3 6
1964#define MC_G4 7
1965#define MC_G5 8
1966#define MC_G6 9
1967#define MC_G7 10
1968#define MC_O0 11
1969#define MC_O1 12
1970#define MC_O2 13
1971#define MC_O3 14
1972#define MC_O4 15
1973#define MC_O5 16
1974#define MC_O6 17
1975#define MC_O7 18
1976#define MC_NGREG 19
1977
blueswir1992f48a2007-10-14 16:27:31 +00001978typedef abi_ulong target_mc_greg_t;
blueswir15bfb56b2007-10-05 17:01:51 +00001979typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
1980
1981struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00001982 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00001983 uint32_t mcfq_insn;
1984};
1985
1986struct target_mc_fpu {
1987 union {
1988 uint32_t sregs[32];
1989 uint64_t dregs[32];
1990 //uint128_t qregs[16];
1991 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00001992 abi_ulong mcfpu_fsr;
1993 abi_ulong mcfpu_fprs;
1994 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00001995 struct target_mc_fq *mcfpu_fq;
1996 unsigned char mcfpu_qcnt;
1997 unsigned char mcfpu_qentsz;
1998 unsigned char mcfpu_enab;
1999};
2000typedef struct target_mc_fpu target_mc_fpu_t;
2001
2002typedef struct {
2003 target_mc_gregset_t mc_gregs;
2004 target_mc_greg_t mc_fp;
2005 target_mc_greg_t mc_i7;
2006 target_mc_fpu_t mc_fpregs;
2007} target_mcontext_t;
2008
2009struct target_ucontext {
2010 struct target_ucontext *uc_link;
blueswir1992f48a2007-10-14 16:27:31 +00002011 abi_ulong uc_flags;
blueswir15bfb56b2007-10-05 17:01:51 +00002012 target_sigset_t uc_sigmask;
2013 target_mcontext_t uc_mcontext;
2014};
2015
2016/* A V9 register window */
2017struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002018 abi_ulong locals[8];
2019 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002020};
2021
2022#define TARGET_STACK_BIAS 2047
2023
2024/* {set, get}context() needed for 64-bit SparcLinux userland. */
2025void sparc64_set_context(CPUSPARCState *env)
2026{
bellard459a4012007-11-11 19:45:10 +00002027 abi_ulong ucp_addr;
2028 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00002029 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002030 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002031 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002032 unsigned char fenab;
2033 int err;
2034 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002035
bellard459a4012007-11-11 19:45:10 +00002036 ucp_addr = env->regwptr[UREG_I0];
2037 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2038 goto do_sigsegv;
blueswir15bfb56b2007-10-05 17:01:51 +00002039 grp = &ucp->uc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002040 err = __get_user(pc, &((*grp)[MC_PC]));
2041 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002042 if (err || ((pc | npc) & 3))
2043 goto do_sigsegv;
2044 if (env->regwptr[UREG_I1]) {
2045 target_sigset_t target_set;
2046 sigset_t set;
2047
2048 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002049 if (__get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002050 goto do_sigsegv;
2051 } else {
bellard459a4012007-11-11 19:45:10 +00002052 abi_ulong *src, *dst;
2053 src = ucp->uc_sigmask.sig;
2054 dst = target_set.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002055 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002056 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002057 err |= __get_user(*dst, src);
blueswir15bfb56b2007-10-05 17:01:51 +00002058 if (err)
2059 goto do_sigsegv;
2060 }
2061 target_to_host_sigset_internal(&set, &target_set);
2062 sigprocmask(SIG_SETMASK, &set, NULL);
2063 }
2064 env->pc = pc;
2065 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002066 err |= __get_user(env->y, &((*grp)[MC_Y]));
2067 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002068 env->asi = (tstate >> 24) & 0xff;
2069 PUT_CCR(env, tstate >> 32);
2070 PUT_CWP64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002071 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2072 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2073 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2074 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2075 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2076 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2077 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2078 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2079 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2080 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2081 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2082 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2083 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2084 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2085 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002086
bellard579a97f2007-11-11 14:26:47 +00002087 err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp));
2088 err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002089
bellard459a4012007-11-11 19:45:10 +00002090 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2091 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2092 abi_ulong) != 0)
2093 goto do_sigsegv;
2094 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2095 abi_ulong) != 0)
2096 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002097 err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
2098 err |= __get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002099 {
2100 uint32_t *src, *dst;
2101 src = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2102 dst = env->fpr;
2103 /* XXX: check that the CPU storage is the same as user context */
2104 for (i = 0; i < 64; i++, dst++, src++)
2105 err |= __get_user(*dst, src);
2106 }
bellard579a97f2007-11-11 14:26:47 +00002107 err |= __get_user(env->fsr,
2108 &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
2109 err |= __get_user(env->gsr,
2110 &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002111 if (err)
2112 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002113 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002114 return;
2115 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002116 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002117 force_sig(SIGSEGV);
2118}
2119
2120void sparc64_get_context(CPUSPARCState *env)
2121{
bellard459a4012007-11-11 19:45:10 +00002122 abi_ulong ucp_addr;
2123 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00002124 target_mc_gregset_t *grp;
2125 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002126 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002127 int err;
2128 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002129 target_sigset_t target_set;
2130 sigset_t set;
2131
bellard459a4012007-11-11 19:45:10 +00002132 ucp_addr = env->regwptr[UREG_I0];
2133 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2134 goto do_sigsegv;
2135
blueswir15bfb56b2007-10-05 17:01:51 +00002136 mcp = &ucp->uc_mcontext;
2137 grp = &mcp->mc_gregs;
2138
2139 /* Skip over the trap instruction, first. */
2140 env->pc = env->npc;
2141 env->npc += 4;
2142
2143 err = 0;
2144
2145 sigprocmask(0, NULL, &set);
2146 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002147 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002148 err |= __put_user(target_set.sig[0],
2149 (abi_ulong *)&ucp->uc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002150 } else {
2151 abi_ulong *src, *dst;
2152 src = target_set.sig;
2153 dst = ucp->uc_sigmask.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002154 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002155 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002156 err |= __put_user(*src, dst);
blueswir15bfb56b2007-10-05 17:01:51 +00002157 if (err)
2158 goto do_sigsegv;
2159 }
2160
bellard459a4012007-11-11 19:45:10 +00002161 /* XXX: tstate must be saved properly */
2162 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002163 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2164 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2165 err |= __put_user(env->y, &((*grp)[MC_Y]));
2166 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2167 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2168 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2169 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2170 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2171 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2172 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2173 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2174 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2175 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2176 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2177 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2178 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2179 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2180 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002181
bellard459a4012007-11-11 19:45:10 +00002182 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2183 fp = i7 = 0;
2184 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2185 abi_ulong) != 0)
2186 goto do_sigsegv;
2187 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2188 abi_ulong) != 0)
2189 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002190 err |= __put_user(fp, &(mcp->mc_fp));
2191 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002192
bellard459a4012007-11-11 19:45:10 +00002193 {
2194 uint32_t *src, *dst;
2195 src = env->fpr;
2196 dst = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2197 /* XXX: check that the CPU storage is the same as user context */
2198 for (i = 0; i < 64; i++, dst++, src++)
2199 err |= __put_user(*src, dst);
2200 }
bellard579a97f2007-11-11 14:26:47 +00002201 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2202 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2203 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002204
2205 if (err)
2206 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002207 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002208 return;
2209 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002210 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002211 force_sig(SIGSEGV);
2212}
2213#endif
thsd26bc212007-11-08 18:05:37 +00002214#elif defined(TARGET_ABI_MIPSN64)
ths540635b2007-09-30 01:58:33 +00002215
2216# warning signal handling not implemented
2217
pbrook624f7972008-05-31 16:11:38 +00002218static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002219 target_sigset_t *set, CPUState *env)
2220{
2221 fprintf(stderr, "setup_frame: not implemented\n");
2222}
2223
pbrook624f7972008-05-31 16:11:38 +00002224static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002225 target_siginfo_t *info,
2226 target_sigset_t *set, CPUState *env)
2227{
2228 fprintf(stderr, "setup_rt_frame: not implemented\n");
2229}
2230
2231long do_sigreturn(CPUState *env)
2232{
2233 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002234 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002235}
2236
2237long do_rt_sigreturn(CPUState *env)
2238{
2239 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002240 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002241}
2242
thsd26bc212007-11-08 18:05:37 +00002243#elif defined(TARGET_ABI_MIPSN32)
ths540635b2007-09-30 01:58:33 +00002244
2245# warning signal handling not implemented
2246
pbrook624f7972008-05-31 16:11:38 +00002247static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002248 target_sigset_t *set, CPUState *env)
2249{
2250 fprintf(stderr, "setup_frame: not implemented\n");
2251}
2252
pbrook624f7972008-05-31 16:11:38 +00002253static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002254 target_siginfo_t *info,
2255 target_sigset_t *set, CPUState *env)
2256{
2257 fprintf(stderr, "setup_rt_frame: not implemented\n");
2258}
2259
2260long do_sigreturn(CPUState *env)
2261{
2262 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002263 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002264}
2265
2266long do_rt_sigreturn(CPUState *env)
2267{
2268 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002269 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002270}
2271
thsd26bc212007-11-08 18:05:37 +00002272#elif defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002273
2274struct target_sigcontext {
2275 uint32_t sc_regmask; /* Unused */
2276 uint32_t sc_status;
2277 uint64_t sc_pc;
2278 uint64_t sc_regs[32];
2279 uint64_t sc_fpregs[32];
2280 uint32_t sc_ownedfp; /* Unused */
2281 uint32_t sc_fpc_csr;
2282 uint32_t sc_fpc_eir; /* Unused */
2283 uint32_t sc_used_math;
2284 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
2285 uint64_t sc_mdhi;
2286 uint64_t sc_mdlo;
2287 target_ulong sc_hi1; /* Was sc_cause */
2288 target_ulong sc_lo1; /* Was sc_badvaddr */
2289 target_ulong sc_hi2; /* Was sc_sigset[4] */
2290 target_ulong sc_lo2;
2291 target_ulong sc_hi3;
2292 target_ulong sc_lo3;
2293};
2294
2295struct sigframe {
2296 uint32_t sf_ass[4]; /* argument save space for o32 */
2297 uint32_t sf_code[2]; /* signal trampoline */
2298 struct target_sigcontext sf_sc;
2299 target_sigset_t sf_mask;
2300};
2301
2302/* Install trampoline to jump back from signal handler */
2303static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2304{
2305 int err;
2306
2307 /*
2308 * Set up the return code ...
2309 *
2310 * li v0, __NR__foo_sigreturn
2311 * syscall
2312 */
2313
2314 err = __put_user(0x24020000 + syscall, tramp + 0);
2315 err |= __put_user(0x0000000c , tramp + 1);
2316 /* flush_cache_sigtramp((unsigned long) tramp); */
2317 return err;
2318}
2319
2320static inline int
2321setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2322{
2323 int err = 0;
2324
thsb5dc7732008-06-27 10:02:35 +00002325 err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002326
thsb5dc7732008-06-27 10:02:35 +00002327#define save_gp_reg(i) do { \
2328 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002329 } while(0)
2330 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
2331 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
2332 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
2333 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
2334 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
2335 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
2336 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
2337 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
2338 save_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002339#undef save_gp_reg
bellard106ec872006-06-27 21:08:10 +00002340
thsb5dc7732008-06-27 10:02:35 +00002341 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2342 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002343
2344 /* Not used yet, but might be useful if we ever have DSP suppport */
2345#if 0
2346 if (cpu_has_dsp) {
2347 err |= __put_user(mfhi1(), &sc->sc_hi1);
2348 err |= __put_user(mflo1(), &sc->sc_lo1);
2349 err |= __put_user(mfhi2(), &sc->sc_hi2);
2350 err |= __put_user(mflo2(), &sc->sc_lo2);
2351 err |= __put_user(mfhi3(), &sc->sc_hi3);
2352 err |= __put_user(mflo3(), &sc->sc_lo3);
2353 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2354 }
2355 /* same with 64 bit */
ths388bb212007-05-13 13:58:00 +00002356#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002357 err |= __put_user(regs->hi, &sc->sc_hi[0]);
2358 err |= __put_user(regs->lo, &sc->sc_lo[0]);
2359 if (cpu_has_dsp) {
2360 err |= __put_user(mfhi1(), &sc->sc_hi[1]);
2361 err |= __put_user(mflo1(), &sc->sc_lo[1]);
2362 err |= __put_user(mfhi2(), &sc->sc_hi[2]);
2363 err |= __put_user(mflo2(), &sc->sc_lo[2]);
2364 err |= __put_user(mfhi3(), &sc->sc_hi[3]);
2365 err |= __put_user(mflo3(), &sc->sc_lo[3]);
2366 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2367 }
ths388bb212007-05-13 13:58:00 +00002368#endif
2369#endif
bellard106ec872006-06-27 21:08:10 +00002370
ths388bb212007-05-13 13:58:00 +00002371#if 0
bellard106ec872006-06-27 21:08:10 +00002372 err |= __put_user(!!used_math(), &sc->sc_used_math);
2373
2374 if (!used_math())
2375 goto out;
2376
2377 /*
2378 * Save FPU state to signal context. Signal handler will "inherit"
2379 * current FPU state.
2380 */
2381 preempt_disable();
2382
2383 if (!is_fpu_owner()) {
2384 own_fpu();
2385 restore_fp(current);
2386 }
2387 err |= save_fp_context(sc);
2388
2389 preempt_enable();
2390 out:
2391#endif
2392 return err;
2393}
2394
2395static inline int
2396restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2397{
2398 int err = 0;
2399
2400 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2401
thsb5dc7732008-06-27 10:02:35 +00002402 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2403 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002404
thsead93602007-09-06 00:18:15 +00002405#define restore_gp_reg(i) do { \
thsb5dc7732008-06-27 10:02:35 +00002406 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002407 } while(0)
2408 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
2409 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
2410 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
2411 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
2412 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
2413 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
2414 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
2415 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
2416 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
2417 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
2418 restore_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002419#undef restore_gp_reg
bellard106ec872006-06-27 21:08:10 +00002420
2421#if 0
2422 if (cpu_has_dsp) {
2423 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
2424 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
2425 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
2426 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
2427 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
2428 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2429 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2430 }
ths388bb212007-05-13 13:58:00 +00002431#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002432 err |= __get_user(regs->hi, &sc->sc_hi[0]);
2433 err |= __get_user(regs->lo, &sc->sc_lo[0]);
2434 if (cpu_has_dsp) {
2435 err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
2436 err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
2437 err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
2438 err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
2439 err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
2440 err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
2441 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2442 }
ths388bb212007-05-13 13:58:00 +00002443#endif
bellard106ec872006-06-27 21:08:10 +00002444
2445 err |= __get_user(used_math, &sc->sc_used_math);
2446 conditional_used_math(used_math);
2447
2448 preempt_disable();
2449
2450 if (used_math()) {
2451 /* restore fpu context if we have used it before */
2452 own_fpu();
2453 err |= restore_fp_context(sc);
2454 } else {
2455 /* signal handler may have used FPU. Give it up. */
2456 lose_fpu();
2457 }
2458
2459 preempt_enable();
2460#endif
2461 return err;
2462}
2463/*
2464 * Determine which stack to use..
2465 */
bellard579a97f2007-11-11 14:26:47 +00002466static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00002467get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002468{
2469 unsigned long sp;
2470
2471 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002472 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002473
2474 /*
2475 * FPU emulator may have it's own trampoline active just
2476 * above the user stack, 16-bytes before the next lowest
2477 * 16 byte boundary. Try to avoid trashing it.
2478 */
2479 sp -= 32;
2480
bellard106ec872006-06-27 21:08:10 +00002481 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002482 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002483 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2484 }
bellard106ec872006-06-27 21:08:10 +00002485
bellard579a97f2007-11-11 14:26:47 +00002486 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002487}
2488
bellard579a97f2007-11-11 14:26:47 +00002489/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002490static void setup_frame(int sig, struct target_sigaction * ka,
bellard579a97f2007-11-11 14:26:47 +00002491 target_sigset_t *set, CPUState *regs)
bellard106ec872006-06-27 21:08:10 +00002492{
2493 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002494 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002495 int i;
2496
bellard579a97f2007-11-11 14:26:47 +00002497 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2498 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002499 goto give_sigsegv;
2500
2501 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2502
2503 if(setup_sigcontext(regs, &frame->sf_sc))
2504 goto give_sigsegv;
2505
2506 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2507 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2508 goto give_sigsegv;
2509 }
2510
2511 /*
2512 * Arguments to signal handler:
2513 *
2514 * a0 = signal number
2515 * a1 = 0 (should be cause)
2516 * a2 = pointer to struct sigcontext
2517 *
2518 * $25 and PC point to the signal handler, $29 points to the
2519 * struct sigframe.
2520 */
thsb5dc7732008-06-27 10:02:35 +00002521 regs->active_tc.gpr[ 4] = sig;
2522 regs->active_tc.gpr[ 5] = 0;
2523 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2524 regs->active_tc.gpr[29] = frame_addr;
2525 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002526 /* The original kernel code sets CP0_EPC to the handler
2527 * since it returns to userland using eret
2528 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002529 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
bellard579a97f2007-11-11 14:26:47 +00002530 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002531 return;
2532
2533give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002534 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002535 force_sig(TARGET_SIGSEGV/*, current*/);
ths5fafdf22007-09-16 21:08:06 +00002536 return;
bellard106ec872006-06-27 21:08:10 +00002537}
2538
2539long do_sigreturn(CPUState *regs)
2540{
ths388bb212007-05-13 13:58:00 +00002541 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002542 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002543 sigset_t blocked;
2544 target_sigset_t target_set;
2545 int i;
bellard106ec872006-06-27 21:08:10 +00002546
2547#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002548 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002549#endif
thsb5dc7732008-06-27 10:02:35 +00002550 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002551 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002552 goto badframe;
2553
ths388bb212007-05-13 13:58:00 +00002554 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002555 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2556 goto badframe;
ths388bb212007-05-13 13:58:00 +00002557 }
bellard106ec872006-06-27 21:08:10 +00002558
ths388bb212007-05-13 13:58:00 +00002559 target_to_host_sigset_internal(&blocked, &target_set);
2560 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002561
ths388bb212007-05-13 13:58:00 +00002562 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002563 goto badframe;
2564
2565#if 0
ths388bb212007-05-13 13:58:00 +00002566 /*
2567 * Don't let your children do this ...
2568 */
2569 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002570 "move\t$29, %0\n\t"
2571 "j\tsyscall_exit"
2572 :/* no outputs */
2573 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002574 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002575#endif
ths3b46e622007-09-17 08:09:54 +00002576
thsb5dc7732008-06-27 10:02:35 +00002577 regs->active_tc.PC = regs->CP0_EPC;
ths388bb212007-05-13 13:58:00 +00002578 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002579 * maybe a problem with nested signals ? */
2580 regs->CP0_EPC = 0;
2581 return 0;
2582
2583badframe:
ths388bb212007-05-13 13:58:00 +00002584 force_sig(TARGET_SIGSEGV/*, current*/);
2585 return 0;
bellard106ec872006-06-27 21:08:10 +00002586}
2587
pbrook624f7972008-05-31 16:11:38 +00002588static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard106ec872006-06-27 21:08:10 +00002589 target_siginfo_t *info,
2590 target_sigset_t *set, CPUState *env)
2591{
2592 fprintf(stderr, "setup_rt_frame: not implemented\n");
2593}
2594
2595long do_rt_sigreturn(CPUState *env)
2596{
2597 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002598 return -TARGET_ENOSYS;
bellard106ec872006-06-27 21:08:10 +00002599}
bellard6d5e2162004-09-30 22:04:13 +00002600
thsc3b5bc82007-12-02 06:31:25 +00002601#elif defined(TARGET_SH4)
2602
2603/*
2604 * code and data structures from linux kernel:
2605 * include/asm-sh/sigcontext.h
2606 * arch/sh/kernel/signal.c
2607 */
2608
2609struct target_sigcontext {
2610 target_ulong oldmask;
2611
2612 /* CPU registers */
2613 target_ulong sc_gregs[16];
2614 target_ulong sc_pc;
2615 target_ulong sc_pr;
2616 target_ulong sc_sr;
2617 target_ulong sc_gbr;
2618 target_ulong sc_mach;
2619 target_ulong sc_macl;
2620
2621 /* FPU registers */
2622 target_ulong sc_fpregs[16];
2623 target_ulong sc_xfpregs[16];
2624 unsigned int sc_fpscr;
2625 unsigned int sc_fpul;
2626 unsigned int sc_ownedfp;
2627};
2628
2629struct target_sigframe
2630{
2631 struct target_sigcontext sc;
2632 target_ulong extramask[TARGET_NSIG_WORDS-1];
2633 uint16_t retcode[3];
2634};
2635
2636
2637struct target_ucontext {
2638 target_ulong uc_flags;
2639 struct target_ucontext *uc_link;
2640 target_stack_t uc_stack;
2641 struct target_sigcontext uc_mcontext;
2642 target_sigset_t uc_sigmask; /* mask last for extensibility */
2643};
2644
2645struct target_rt_sigframe
2646{
2647 struct target_siginfo info;
2648 struct target_ucontext uc;
2649 uint16_t retcode[3];
2650};
2651
2652
2653#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
2654#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
2655
pbrook624f7972008-05-31 16:11:38 +00002656static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002657 unsigned long sp, size_t frame_size)
2658{
pbrook624f7972008-05-31 16:11:38 +00002659 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00002660 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2661 }
2662
2663 return (sp - frame_size) & -8ul;
2664}
2665
2666static int setup_sigcontext(struct target_sigcontext *sc,
2667 CPUState *regs, unsigned long mask)
2668{
2669 int err = 0;
2670
2671#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
2672 COPY(gregs[0]); COPY(gregs[1]);
2673 COPY(gregs[2]); COPY(gregs[3]);
2674 COPY(gregs[4]); COPY(gregs[5]);
2675 COPY(gregs[6]); COPY(gregs[7]);
2676 COPY(gregs[8]); COPY(gregs[9]);
2677 COPY(gregs[10]); COPY(gregs[11]);
2678 COPY(gregs[12]); COPY(gregs[13]);
2679 COPY(gregs[14]); COPY(gregs[15]);
2680 COPY(gbr); COPY(mach);
2681 COPY(macl); COPY(pr);
2682 COPY(sr); COPY(pc);
2683#undef COPY
2684
2685 /* todo: save FPU registers here */
2686
2687 /* non-iBCS2 extensions.. */
2688 err |= __put_user(mask, &sc->oldmask);
2689
2690 return err;
2691}
2692
2693static int restore_sigcontext(struct CPUState *regs,
2694 struct target_sigcontext *sc)
2695{
2696 unsigned int err = 0;
2697
2698#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
2699 COPY(gregs[1]);
2700 COPY(gregs[2]); COPY(gregs[3]);
2701 COPY(gregs[4]); COPY(gregs[5]);
2702 COPY(gregs[6]); COPY(gregs[7]);
2703 COPY(gregs[8]); COPY(gregs[9]);
2704 COPY(gregs[10]); COPY(gregs[11]);
2705 COPY(gregs[12]); COPY(gregs[13]);
2706 COPY(gregs[14]); COPY(gregs[15]);
2707 COPY(gbr); COPY(mach);
2708 COPY(macl); COPY(pr);
2709 COPY(sr); COPY(pc);
2710#undef COPY
2711
2712 /* todo: restore FPU registers here */
2713
2714 regs->tra = -1; /* disable syscall checks */
2715 return err;
2716}
2717
pbrook624f7972008-05-31 16:11:38 +00002718static void setup_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002719 target_sigset_t *set, CPUState *regs)
2720{
2721 struct target_sigframe *frame;
2722 abi_ulong frame_addr;
2723 int i;
2724 int err = 0;
2725 int signal;
2726
2727 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2728 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2729 goto give_sigsegv;
2730
2731 signal = current_exec_domain_sig(sig);
2732
2733 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
2734
2735 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2736 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
2737 }
2738
2739 /* Set up to return from userspace. If provided, use a stub
2740 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002741 if (ka->sa_flags & TARGET_SA_RESTORER) {
2742 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002743 } else {
2744 /* Generate return code (system call to sigreturn) */
2745 err |= __put_user(MOVW(2), &frame->retcode[0]);
2746 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2747 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
2748 regs->pr = (unsigned long) frame->retcode;
2749 }
2750
2751 if (err)
2752 goto give_sigsegv;
2753
2754 /* Set up registers for signal handler */
2755 regs->gregs[15] = (unsigned long) frame;
2756 regs->gregs[4] = signal; /* Arg for signal handler */
2757 regs->gregs[5] = 0;
2758 regs->gregs[6] = (unsigned long) &frame->sc;
pbrook624f7972008-05-31 16:11:38 +00002759 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002760
2761 unlock_user_struct(frame, frame_addr, 1);
2762 return;
2763
2764give_sigsegv:
2765 unlock_user_struct(frame, frame_addr, 1);
2766 force_sig(SIGSEGV);
2767}
2768
pbrook624f7972008-05-31 16:11:38 +00002769static void setup_rt_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002770 target_siginfo_t *info,
2771 target_sigset_t *set, CPUState *regs)
2772{
2773 struct target_rt_sigframe *frame;
2774 abi_ulong frame_addr;
2775 int i;
2776 int err = 0;
2777 int signal;
2778
2779 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2780 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2781 goto give_sigsegv;
2782
2783 signal = current_exec_domain_sig(sig);
2784
2785 err |= copy_siginfo_to_user(&frame->info, info);
2786
2787 /* Create the ucontext. */
2788 err |= __put_user(0, &frame->uc.uc_flags);
2789 err |= __put_user(0, (unsigned long *)&frame->uc.uc_link);
balrog526ccb72008-07-16 12:13:52 +00002790 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
thsc3b5bc82007-12-02 06:31:25 +00002791 &frame->uc.uc_stack.ss_sp);
2792 err |= __put_user(sas_ss_flags(regs->gregs[15]),
2793 &frame->uc.uc_stack.ss_flags);
2794 err |= __put_user(target_sigaltstack_used.ss_size,
2795 &frame->uc.uc_stack.ss_size);
2796 err |= setup_sigcontext(&frame->uc.uc_mcontext,
2797 regs, set->sig[0]);
2798 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2799 err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]);
2800 }
2801
2802 /* Set up to return from userspace. If provided, use a stub
2803 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002804 if (ka->sa_flags & TARGET_SA_RESTORER) {
2805 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002806 } else {
2807 /* Generate return code (system call to sigreturn) */
2808 err |= __put_user(MOVW(2), &frame->retcode[0]);
2809 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2810 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
2811 regs->pr = (unsigned long) frame->retcode;
2812 }
2813
2814 if (err)
2815 goto give_sigsegv;
2816
2817 /* Set up registers for signal handler */
2818 regs->gregs[15] = (unsigned long) frame;
2819 regs->gregs[4] = signal; /* Arg for signal handler */
2820 regs->gregs[5] = (unsigned long) &frame->info;
2821 regs->gregs[6] = (unsigned long) &frame->uc;
pbrook624f7972008-05-31 16:11:38 +00002822 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002823
2824 unlock_user_struct(frame, frame_addr, 1);
2825 return;
2826
2827give_sigsegv:
2828 unlock_user_struct(frame, frame_addr, 1);
2829 force_sig(SIGSEGV);
2830}
2831
2832long do_sigreturn(CPUState *regs)
2833{
2834 struct target_sigframe *frame;
2835 abi_ulong frame_addr;
2836 sigset_t blocked;
2837 target_sigset_t target_set;
2838 int i;
2839 int err = 0;
2840
2841#if defined(DEBUG_SIGNAL)
2842 fprintf(stderr, "do_sigreturn\n");
2843#endif
2844 frame_addr = regs->gregs[15];
2845 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2846 goto badframe;
2847
2848 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
2849 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2850 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
2851 }
2852
2853 if (err)
2854 goto badframe;
2855
2856 target_to_host_sigset_internal(&blocked, &target_set);
2857 sigprocmask(SIG_SETMASK, &blocked, NULL);
2858
2859 if (restore_sigcontext(regs, &frame->sc))
2860 goto badframe;
2861
2862 unlock_user_struct(frame, frame_addr, 0);
2863 return regs->gregs[0];
2864
2865badframe:
2866 unlock_user_struct(frame, frame_addr, 0);
2867 force_sig(TARGET_SIGSEGV);
2868 return 0;
2869}
2870
2871long do_rt_sigreturn(CPUState *regs)
2872{
2873 struct target_rt_sigframe *frame;
2874 abi_ulong frame_addr;
2875 sigset_t blocked;
2876
2877#if defined(DEBUG_SIGNAL)
2878 fprintf(stderr, "do_rt_sigreturn\n");
2879#endif
2880 frame_addr = regs->gregs[15];
2881 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2882 goto badframe;
2883
2884 target_to_host_sigset(&blocked, &frame->uc.uc_sigmask);
2885 sigprocmask(SIG_SETMASK, &blocked, NULL);
2886
2887 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
2888 goto badframe;
2889
2890 if (do_sigaltstack(frame_addr +
2891 offsetof(struct target_rt_sigframe, uc.uc_stack),
2892 0, get_sp_from_cpustate(regs)) == -EFAULT)
2893 goto badframe;
2894
2895 unlock_user_struct(frame, frame_addr, 0);
2896 return regs->gregs[0];
2897
2898badframe:
2899 unlock_user_struct(frame, frame_addr, 0);
2900 force_sig(TARGET_SIGSEGV);
2901 return 0;
2902}
edgar_iglb6d3abd2008-02-28 11:29:27 +00002903#elif defined(TARGET_CRIS)
2904
2905struct target_sigcontext {
2906 struct target_pt_regs regs; /* needs to be first */
2907 uint32_t oldmask;
2908 uint32_t usp; /* usp before stacking this gunk on it */
2909};
2910
2911/* Signal frames. */
2912struct target_signal_frame {
2913 struct target_sigcontext sc;
2914 uint32_t extramask[TARGET_NSIG_WORDS - 1];
2915 uint8_t retcode[8]; /* Trampoline code. */
2916};
2917
2918struct rt_signal_frame {
2919 struct siginfo *pinfo;
2920 void *puc;
2921 struct siginfo info;
2922 struct ucontext uc;
2923 uint8_t retcode[8]; /* Trampoline code. */
2924};
2925
2926static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
2927{
edgar_igl9664d922008-03-03 22:23:53 +00002928 __put_user(env->regs[0], &sc->regs.r0);
2929 __put_user(env->regs[1], &sc->regs.r1);
2930 __put_user(env->regs[2], &sc->regs.r2);
2931 __put_user(env->regs[3], &sc->regs.r3);
2932 __put_user(env->regs[4], &sc->regs.r4);
2933 __put_user(env->regs[5], &sc->regs.r5);
2934 __put_user(env->regs[6], &sc->regs.r6);
2935 __put_user(env->regs[7], &sc->regs.r7);
2936 __put_user(env->regs[8], &sc->regs.r8);
2937 __put_user(env->regs[9], &sc->regs.r9);
2938 __put_user(env->regs[10], &sc->regs.r10);
2939 __put_user(env->regs[11], &sc->regs.r11);
2940 __put_user(env->regs[12], &sc->regs.r12);
2941 __put_user(env->regs[13], &sc->regs.r13);
2942 __put_user(env->regs[14], &sc->usp);
2943 __put_user(env->regs[15], &sc->regs.acr);
2944 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
2945 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
2946 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002947}
edgar_igl9664d922008-03-03 22:23:53 +00002948
edgar_iglb6d3abd2008-02-28 11:29:27 +00002949static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
2950{
edgar_igl9664d922008-03-03 22:23:53 +00002951 __get_user(env->regs[0], &sc->regs.r0);
2952 __get_user(env->regs[1], &sc->regs.r1);
2953 __get_user(env->regs[2], &sc->regs.r2);
2954 __get_user(env->regs[3], &sc->regs.r3);
2955 __get_user(env->regs[4], &sc->regs.r4);
2956 __get_user(env->regs[5], &sc->regs.r5);
2957 __get_user(env->regs[6], &sc->regs.r6);
2958 __get_user(env->regs[7], &sc->regs.r7);
2959 __get_user(env->regs[8], &sc->regs.r8);
2960 __get_user(env->regs[9], &sc->regs.r9);
2961 __get_user(env->regs[10], &sc->regs.r10);
2962 __get_user(env->regs[11], &sc->regs.r11);
2963 __get_user(env->regs[12], &sc->regs.r12);
2964 __get_user(env->regs[13], &sc->regs.r13);
2965 __get_user(env->regs[14], &sc->usp);
2966 __get_user(env->regs[15], &sc->regs.acr);
2967 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
2968 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
2969 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002970}
2971
edgar_igl9664d922008-03-03 22:23:53 +00002972static abi_ulong get_sigframe(CPUState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00002973{
edgar_igl9664d922008-03-03 22:23:53 +00002974 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002975 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00002976 sp = (env->regs[R_SP] & ~3);
2977 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002978}
2979
pbrook624f7972008-05-31 16:11:38 +00002980static void setup_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00002981 target_sigset_t *set, CPUState *env)
2982{
2983 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00002984 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002985 int err = 0;
2986 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002987
edgar_igl9664d922008-03-03 22:23:53 +00002988 frame_addr = get_sigframe(env, sizeof *frame);
2989 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00002990 goto badframe;
2991
2992 /*
2993 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
2994 * use this trampoline anymore but it sets it up for GDB.
2995 * In QEMU, using the trampoline simplifies things a bit so we use it.
2996 *
2997 * This is movu.w __NR_sigreturn, r9; break 13;
2998 */
2999 err |= __put_user(0x9c5f, frame->retcode+0);
3000 err |= __put_user(TARGET_NR_sigreturn,
3001 frame->retcode+2);
3002 err |= __put_user(0xe93d, frame->retcode+4);
3003
3004 /* Save the mask. */
3005 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3006 if (err)
3007 goto badframe;
3008
3009 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3010 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3011 goto badframe;
3012 }
3013
3014 setup_sigcontext(&frame->sc, env);
3015
3016 /* Move the stack and setup the arguments for the handler. */
balrog526ccb72008-07-16 12:13:52 +00003017 env->regs[R_SP] = (uint32_t) (unsigned long) frame;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003018 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003019 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003020 /* Link SRP so the guest returns through the trampoline. */
balrog526ccb72008-07-16 12:13:52 +00003021 env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003022
edgar_igl9664d922008-03-03 22:23:53 +00003023 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003024 return;
3025 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003026 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003027 force_sig(TARGET_SIGSEGV);
3028}
3029
pbrook624f7972008-05-31 16:11:38 +00003030static void setup_rt_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00003031 target_siginfo_t *info,
3032 target_sigset_t *set, CPUState *env)
3033{
3034 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3035}
3036
3037long do_sigreturn(CPUState *env)
3038{
3039 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003040 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003041 target_sigset_t target_set;
3042 sigset_t set;
3043 int i;
3044
edgar_igl9664d922008-03-03 22:23:53 +00003045 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003046 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003047 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003048 goto badframe;
3049
3050 /* Restore blocked signals */
3051 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3052 goto badframe;
3053 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3054 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3055 goto badframe;
3056 }
3057 target_to_host_sigset_internal(&set, &target_set);
3058 sigprocmask(SIG_SETMASK, &set, NULL);
3059
3060 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003061 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003062 return env->regs[10];
3063 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003064 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003065 force_sig(TARGET_SIGSEGV);
3066}
3067
3068long do_rt_sigreturn(CPUState *env)
3069{
3070 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3071 return -TARGET_ENOSYS;
3072}
thsc3b5bc82007-12-02 06:31:25 +00003073
bellardb346ff42003-06-15 20:05:50 +00003074#else
3075
pbrook624f7972008-05-31 16:11:38 +00003076static void setup_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003077 target_sigset_t *set, CPUState *env)
3078{
3079 fprintf(stderr, "setup_frame: not implemented\n");
3080}
3081
pbrook624f7972008-05-31 16:11:38 +00003082static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003083 target_siginfo_t *info,
3084 target_sigset_t *set, CPUState *env)
3085{
3086 fprintf(stderr, "setup_rt_frame: not implemented\n");
3087}
3088
3089long do_sigreturn(CPUState *env)
3090{
3091 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003092 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003093}
3094
3095long do_rt_sigreturn(CPUState *env)
3096{
3097 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003098 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003099}
3100
bellard66fb9762003-03-23 01:06:05 +00003101#endif
3102
pbrook624f7972008-05-31 16:11:38 +00003103void process_pending_signals(CPUState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00003104{
3105 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00003106 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00003107 sigset_t set, old_set;
3108 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00003109 struct emulated_sigtable *k;
3110 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00003111 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00003112 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00003113
pbrook624f7972008-05-31 16:11:38 +00003114 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00003115 return;
3116
pbrook624f7972008-05-31 16:11:38 +00003117 /* FIXME: This is not threadsafe. */
3118 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00003119 for(sig = 1; sig <= TARGET_NSIG; sig++) {
3120 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00003121 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00003122 k++;
bellard31e31b82003-02-18 22:55:36 +00003123 }
3124 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00003125 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00003126 return;
bellard66fb9762003-03-23 01:06:05 +00003127
bellard31e31b82003-02-18 22:55:36 +00003128 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00003129#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00003130 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00003131#endif
3132 /* dequeue signal */
3133 q = k->first;
3134 k->first = q->next;
3135 if (!k->first)
3136 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00003137
bellard1fddef42005-04-17 19:16:13 +00003138 sig = gdb_handlesig (cpu_env, sig);
3139 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00003140 sa = NULL;
3141 handler = TARGET_SIG_IGN;
3142 } else {
3143 sa = &sigact_table[sig - 1];
3144 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00003145 }
bellard66fb9762003-03-23 01:06:05 +00003146
bellard66fb9762003-03-23 01:06:05 +00003147 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00003148 /* default handler : ignore some signal. The other are job control or fatal */
3149 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
3150 kill(getpid(),SIGSTOP);
3151 } else if (sig != TARGET_SIGCHLD &&
3152 sig != TARGET_SIGURG &&
3153 sig != TARGET_SIGWINCH &&
3154 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00003155 force_sig(sig);
3156 }
3157 } else if (handler == TARGET_SIG_IGN) {
3158 /* ignore sig */
3159 } else if (handler == TARGET_SIG_ERR) {
3160 force_sig(sig);
3161 } else {
bellard9de5e442003-03-23 16:49:39 +00003162 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00003163 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00003164 /* SA_NODEFER indicates that the current signal should not be
3165 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00003166 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00003167 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00003168
bellard9de5e442003-03-23 16:49:39 +00003169 /* block signals in the handler using Linux */
3170 sigprocmask(SIG_BLOCK, &set, &old_set);
3171 /* save the previous blocked signal state to restore it at the
3172 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00003173 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00003174
bellardbc8a22c2003-03-30 21:02:40 +00003175 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00003176#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00003177 {
3178 CPUX86State *env = cpu_env;
3179 if (env->eflags & VM_MASK)
3180 save_v86_state(env);
3181 }
3182#endif
bellard9de5e442003-03-23 16:49:39 +00003183 /* prepare the stack frame of the virtual CPU */
pbrook624f7972008-05-31 16:11:38 +00003184 if (sa->sa_flags & TARGET_SA_SIGINFO)
3185 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00003186 else
pbrook624f7972008-05-31 16:11:38 +00003187 setup_frame(sig, sa, &target_old_set, cpu_env);
3188 if (sa->sa_flags & TARGET_SA_RESETHAND)
3189 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00003190 }
bellard66fb9762003-03-23 01:06:05 +00003191 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00003192 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00003193}