blob: ae1c0bac23e02c96a06ec699f9cf1a1b058e7c83 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20#include <stdlib.h>
21#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000022#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000023#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000024#include <unistd.h>
bellard31e31b82003-02-18 22:55:36 +000025#include <signal.h>
bellard66fb9762003-03-23 01:06:05 +000026#include <errno.h>
bellard31e31b82003-02-18 22:55:36 +000027#include <sys/ucontext.h>
28
bellard3ef693a2003-03-23 20:17:16 +000029#include "qemu.h"
blueswir1992f48a2007-10-14 16:27:31 +000030#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000031
32//#define DEBUG_SIGNAL
33
blueswir1249c4c32008-10-05 11:09:37 +000034static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000035 .ss_sp = 0,
36 .ss_size = 0,
37 .ss_flags = TARGET_SS_DISABLE,
38};
39
pbrook624f7972008-05-31 16:11:38 +000040static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000041
ths5fafdf22007-09-16 21:08:06 +000042static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000043 void *puc);
44
bellard9e5f5282003-07-13 17:33:54 +000045static uint8_t host_to_target_signal_table[65] = {
46 [SIGHUP] = TARGET_SIGHUP,
47 [SIGINT] = TARGET_SIGINT,
48 [SIGQUIT] = TARGET_SIGQUIT,
49 [SIGILL] = TARGET_SIGILL,
50 [SIGTRAP] = TARGET_SIGTRAP,
51 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000052/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000053 [SIGBUS] = TARGET_SIGBUS,
54 [SIGFPE] = TARGET_SIGFPE,
55 [SIGKILL] = TARGET_SIGKILL,
56 [SIGUSR1] = TARGET_SIGUSR1,
57 [SIGSEGV] = TARGET_SIGSEGV,
58 [SIGUSR2] = TARGET_SIGUSR2,
59 [SIGPIPE] = TARGET_SIGPIPE,
60 [SIGALRM] = TARGET_SIGALRM,
61 [SIGTERM] = TARGET_SIGTERM,
62#ifdef SIGSTKFLT
63 [SIGSTKFLT] = TARGET_SIGSTKFLT,
64#endif
65 [SIGCHLD] = TARGET_SIGCHLD,
66 [SIGCONT] = TARGET_SIGCONT,
67 [SIGSTOP] = TARGET_SIGSTOP,
68 [SIGTSTP] = TARGET_SIGTSTP,
69 [SIGTTIN] = TARGET_SIGTTIN,
70 [SIGTTOU] = TARGET_SIGTTOU,
71 [SIGURG] = TARGET_SIGURG,
72 [SIGXCPU] = TARGET_SIGXCPU,
73 [SIGXFSZ] = TARGET_SIGXFSZ,
74 [SIGVTALRM] = TARGET_SIGVTALRM,
75 [SIGPROF] = TARGET_SIGPROF,
76 [SIGWINCH] = TARGET_SIGWINCH,
77 [SIGIO] = TARGET_SIGIO,
78 [SIGPWR] = TARGET_SIGPWR,
79 [SIGSYS] = TARGET_SIGSYS,
80 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000081 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
82 host libpthread signals. This assumes noone actually uses SIGRTMAX :-/
83 To fix this properly we need to do manual signal delivery multiplexed
84 over a single host signal. */
85 [__SIGRTMIN] = __SIGRTMAX,
86 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000087};
88static uint8_t target_to_host_signal_table[65];
89
thsa04e1342007-09-27 13:57:58 +000090static inline int on_sig_stack(unsigned long sp)
91{
92 return (sp - target_sigaltstack_used.ss_sp
93 < target_sigaltstack_used.ss_size);
94}
95
96static inline int sas_ss_flags(unsigned long sp)
97{
98 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
99 : on_sig_stack(sp) ? SS_ONSTACK : 0);
100}
101
bellard31e31b82003-02-18 22:55:36 +0000102static inline int host_to_target_signal(int sig)
103{
pbrook4cb05962008-05-30 18:05:19 +0000104 if (sig > 64)
105 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000106 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000107}
108
pbrook4cb05962008-05-30 18:05:19 +0000109int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000110{
pbrook4cb05962008-05-30 18:05:19 +0000111 if (sig > 64)
112 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000113 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000114}
115
pbrookf5545b52008-05-30 22:37:07 +0000116static inline void target_sigemptyset(target_sigset_t *set)
117{
118 memset(set, 0, sizeof(*set));
119}
120
121static inline void target_sigaddset(target_sigset_t *set, int signum)
122{
123 signum--;
124 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
125 set->sig[signum / TARGET_NSIG_BPW] |= mask;
126}
127
128static inline int target_sigismember(const target_sigset_t *set, int signum)
129{
130 signum--;
131 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
132 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
133}
134
ths5fafdf22007-09-16 21:08:06 +0000135static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000136 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000137{
138 int i;
pbrookf5545b52008-05-30 22:37:07 +0000139 target_sigemptyset(d);
140 for (i = 1; i <= TARGET_NSIG; i++) {
141 if (sigismember(s, i)) {
142 target_sigaddset(d, host_to_target_signal(i));
143 }
bellard9e5f5282003-07-13 17:33:54 +0000144 }
bellard66fb9762003-03-23 01:06:05 +0000145}
146
bellard92319442004-06-19 16:58:13 +0000147void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
148{
149 target_sigset_t d1;
150 int i;
151
152 host_to_target_sigset_internal(&d1, s);
153 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000154 d->sig[i] = tswapl(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000155}
156
blueswir18fcd3692008-08-17 20:26:25 +0000157static void target_to_host_sigset_internal(sigset_t *d,
158 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000159{
160 int i;
pbrookf5545b52008-05-30 22:37:07 +0000161 sigemptyset(d);
162 for (i = 1; i <= TARGET_NSIG; i++) {
163 if (target_sigismember(s, i)) {
164 sigaddset(d, target_to_host_signal(i));
165 }
166 }
bellard66fb9762003-03-23 01:06:05 +0000167}
168
bellard92319442004-06-19 16:58:13 +0000169void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
170{
171 target_sigset_t s1;
172 int i;
173
174 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000175 s1.sig[i] = tswapl(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000176 target_to_host_sigset_internal(d, &s1);
177}
ths3b46e622007-09-17 08:09:54 +0000178
blueswir1992f48a2007-10-14 16:27:31 +0000179void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000180 const sigset_t *sigset)
181{
bellard9e5f5282003-07-13 17:33:54 +0000182 target_sigset_t d;
183 host_to_target_sigset(&d, sigset);
184 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000185}
186
ths5fafdf22007-09-16 21:08:06 +0000187void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000188 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000189{
bellard9e5f5282003-07-13 17:33:54 +0000190 target_sigset_t d;
191 int i;
192
193 d.sig[0] = *old_sigset;
194 for(i = 1;i < TARGET_NSIG_WORDS; i++)
195 d.sig[i] = 0;
196 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000197}
198
bellard9de5e442003-03-23 16:49:39 +0000199/* siginfo conversion */
200
ths5fafdf22007-09-16 21:08:06 +0000201static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000202 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000203{
bellard9de5e442003-03-23 16:49:39 +0000204 int sig;
205 sig = host_to_target_signal(info->si_signo);
206 tinfo->si_signo = sig;
207 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000208 tinfo->si_code = info->si_code;
ths5fafdf22007-09-16 21:08:06 +0000209 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000210 sig == SIGBUS || sig == SIGTRAP) {
bellard9de5e442003-03-23 16:49:39 +0000211 /* should never come here, but who knows. The information for
212 the target is irrelevant */
213 tinfo->_sifields._sigfault._addr = 0;
ths7f7f7c82007-07-12 11:02:46 +0000214 } else if (sig == SIGIO) {
215 tinfo->_sifields._sigpoll._fd = info->si_fd;
bellard9de5e442003-03-23 16:49:39 +0000216 } else if (sig >= TARGET_SIGRTMIN) {
217 tinfo->_sifields._rt._pid = info->si_pid;
218 tinfo->_sifields._rt._uid = info->si_uid;
219 /* XXX: potential problem if 64 bit */
ths5fafdf22007-09-16 21:08:06 +0000220 tinfo->_sifields._rt._sigval.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000221 (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000222 }
bellard66fb9762003-03-23 01:06:05 +0000223}
224
ths5fafdf22007-09-16 21:08:06 +0000225static void tswap_siginfo(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000226 const target_siginfo_t *info)
227{
228 int sig;
229 sig = info->si_signo;
230 tinfo->si_signo = tswap32(sig);
231 tinfo->si_errno = tswap32(info->si_errno);
232 tinfo->si_code = tswap32(info->si_code);
ths5fafdf22007-09-16 21:08:06 +0000233 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000234 sig == SIGBUS || sig == SIGTRAP) {
ths5fafdf22007-09-16 21:08:06 +0000235 tinfo->_sifields._sigfault._addr =
bellard9de5e442003-03-23 16:49:39 +0000236 tswapl(info->_sifields._sigfault._addr);
ths7f7f7c82007-07-12 11:02:46 +0000237 } else if (sig == SIGIO) {
238 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
bellard9de5e442003-03-23 16:49:39 +0000239 } else if (sig >= TARGET_SIGRTMIN) {
240 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
241 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000242 tinfo->_sifields._rt._sigval.sival_ptr =
bellard9de5e442003-03-23 16:49:39 +0000243 tswapl(info->_sifields._rt._sigval.sival_ptr);
244 }
245}
246
247
248void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
249{
250 host_to_target_siginfo_noswap(tinfo, info);
251 tswap_siginfo(tinfo, tinfo);
252}
253
254/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000255/* XXX: find a solution for 64 bit (additional malloced data is needed) */
bellard9de5e442003-03-23 16:49:39 +0000256void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000257{
258 info->si_signo = tswap32(tinfo->si_signo);
259 info->si_errno = tswap32(tinfo->si_errno);
260 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000261 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
262 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000263 info->si_value.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000264 (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000265}
266
aurel32ca587a82008-12-18 22:44:13 +0000267static int fatal_signal (int sig)
268{
269 switch (sig) {
270 case TARGET_SIGCHLD:
271 case TARGET_SIGURG:
272 case TARGET_SIGWINCH:
273 /* Ignored by default. */
274 return 0;
275 case TARGET_SIGCONT:
276 case TARGET_SIGSTOP:
277 case TARGET_SIGTSTP:
278 case TARGET_SIGTTIN:
279 case TARGET_SIGTTOU:
280 /* Job control signals. */
281 return 0;
282 default:
283 return 1;
284 }
285}
286
bellard31e31b82003-02-18 22:55:36 +0000287void signal_init(void)
288{
289 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000290 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000291 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000292 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000293
bellard9e5f5282003-07-13 17:33:54 +0000294 /* generate signal conversion tables */
295 for(i = 1; i <= 64; i++) {
296 if (host_to_target_signal_table[i] == 0)
297 host_to_target_signal_table[i] = i;
298 }
299 for(i = 1; i <= 64; i++) {
300 j = host_to_target_signal_table[i];
301 target_to_host_signal_table[j] = i;
302 }
ths3b46e622007-09-17 08:09:54 +0000303
bellard9de5e442003-03-23 16:49:39 +0000304 /* set all host signal handlers. ALL signals are blocked during
305 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000306 memset(sigact_table, 0, sizeof(sigact_table));
307
bellard9de5e442003-03-23 16:49:39 +0000308 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000309 act.sa_flags = SA_SIGINFO;
310 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000311 for(i = 1; i <= TARGET_NSIG; i++) {
312 host_sig = target_to_host_signal(i);
313 sigaction(host_sig, NULL, &oact);
314 if (oact.sa_sigaction == (void *)SIG_IGN) {
315 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
316 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
317 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
318 }
319 /* If there's already a handler installed then something has
320 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000321 /* Install some handlers for our own use. We need at least
322 SIGSEGV and SIGBUS, to detect exceptions. We can not just
323 trap all signals because it affects syscall interrupt
324 behavior. But do trap all default-fatal signals. */
325 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000326 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000327 }
bellard31e31b82003-02-18 22:55:36 +0000328}
329
bellard66fb9762003-03-23 01:06:05 +0000330/* signal queue handling */
331
pbrook624f7972008-05-31 16:11:38 +0000332static inline struct sigqueue *alloc_sigqueue(CPUState *env)
bellard66fb9762003-03-23 01:06:05 +0000333{
pbrook624f7972008-05-31 16:11:38 +0000334 TaskState *ts = env->opaque;
335 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000336 if (!q)
337 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000338 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000339 return q;
340}
341
pbrook624f7972008-05-31 16:11:38 +0000342static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000343{
pbrook624f7972008-05-31 16:11:38 +0000344 TaskState *ts = env->opaque;
345 q->next = ts->first_free;
346 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000347}
348
bellard9de5e442003-03-23 16:49:39 +0000349/* abort execution with signal */
blueswir18fcd3692008-08-17 20:26:25 +0000350static void __attribute((noreturn)) force_sig(int sig)
bellard66fb9762003-03-23 01:06:05 +0000351{
352 int host_sig;
bellard66fb9762003-03-23 01:06:05 +0000353 host_sig = target_to_host_signal(sig);
ths5fafdf22007-09-16 21:08:06 +0000354 fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
bellard66fb9762003-03-23 01:06:05 +0000355 sig, strsignal(host_sig));
bellard9de5e442003-03-23 16:49:39 +0000356#if 1
aurel32ca587a82008-12-18 22:44:13 +0000357 gdb_signalled(thread_env, sig);
bellard66fb9762003-03-23 01:06:05 +0000358 _exit(-host_sig);
bellard9de5e442003-03-23 16:49:39 +0000359#else
360 {
361 struct sigaction act;
362 sigemptyset(&act.sa_mask);
363 act.sa_flags = SA_SIGINFO;
364 act.sa_sigaction = SIG_DFL;
365 sigaction(SIGABRT, &act, NULL);
366 abort();
367 }
368#endif
bellard66fb9762003-03-23 01:06:05 +0000369}
370
bellard9de5e442003-03-23 16:49:39 +0000371/* queue a signal so that it will be send to the virtual CPU as soon
372 as possible */
pbrook624f7972008-05-31 16:11:38 +0000373int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000374{
pbrook624f7972008-05-31 16:11:38 +0000375 TaskState *ts = env->opaque;
376 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000377 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000378 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000379 int queue;
bellard66fb9762003-03-23 01:06:05 +0000380
bellard9de5e442003-03-23 16:49:39 +0000381#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000382 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000383 sig);
bellard66fb9762003-03-23 01:06:05 +0000384#endif
pbrook624f7972008-05-31 16:11:38 +0000385 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000386 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000387 handler = sigact_table[sig - 1]._sa_handler;
aurel32ca587a82008-12-18 22:44:13 +0000388 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000389 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
390 kill(getpid(),SIGSTOP);
391 return 0;
392 } else
bellard66fb9762003-03-23 01:06:05 +0000393 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000394 if (sig != TARGET_SIGCHLD &&
395 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000396 sig != TARGET_SIGWINCH &&
397 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000398 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000399 } else {
400 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000401 }
aurel32ca587a82008-12-18 22:44:13 +0000402 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000403 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000404 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000405 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000406 force_sig(sig);
407 } else {
bellard9de5e442003-03-23 16:49:39 +0000408 pq = &k->first;
409 if (sig < TARGET_SIGRTMIN) {
410 /* if non real time signal, we queue exactly one signal */
411 if (!k->pending)
412 q = &k->info;
413 else
414 return 0;
415 } else {
416 if (!k->pending) {
417 /* first signal */
418 q = &k->info;
419 } else {
pbrook624f7972008-05-31 16:11:38 +0000420 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000421 if (!q)
422 return -EAGAIN;
423 while (*pq != NULL)
424 pq = &(*pq)->next;
425 }
426 }
427 *pq = q;
428 q->info = *info;
429 q->next = NULL;
430 k->pending = 1;
431 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000432 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000433 return 1; /* indicates that the signal was queued */
434 }
435}
436
ths5fafdf22007-09-16 21:08:06 +0000437static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000438 void *puc)
439{
440 int sig;
441 target_siginfo_t tinfo;
442
443 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000444 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000445 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000446 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000447 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000448 return;
449 }
450
451 /* get target signal number */
452 sig = host_to_target_signal(host_signum);
453 if (sig < 1 || sig > TARGET_NSIG)
454 return;
455#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000456 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000457#endif
458 host_to_target_siginfo_noswap(&tinfo, info);
pbrookd5975362008-06-07 20:50:51 +0000459 if (queue_signal(thread_env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000460 /* interrupt the virtual CPU as soon as possible */
pbrookd5975362008-06-07 20:50:51 +0000461 cpu_interrupt(thread_env, CPU_INTERRUPT_EXIT);
bellard66fb9762003-03-23 01:06:05 +0000462 }
bellard31e31b82003-02-18 22:55:36 +0000463}
464
ths0da46a62007-10-20 20:23:07 +0000465/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000466/* compare linux/kernel/signal.c:do_sigaltstack() */
467abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000468{
469 int ret;
470 struct target_sigaltstack oss;
471
472 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000473 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000474 {
475 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
476 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
477 __put_user(sas_ss_flags(sp), &oss.ss_flags);
478 }
479
bellard579a97f2007-11-11 14:26:47 +0000480 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000481 {
bellard579a97f2007-11-11 14:26:47 +0000482 struct target_sigaltstack *uss;
483 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000484
ths0da46a62007-10-20 20:23:07 +0000485 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000486 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000487 || __get_user(ss.ss_sp, &uss->ss_sp)
488 || __get_user(ss.ss_size, &uss->ss_size)
489 || __get_user(ss.ss_flags, &uss->ss_flags))
490 goto out;
bellard579a97f2007-11-11 14:26:47 +0000491 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000492
ths0da46a62007-10-20 20:23:07 +0000493 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000494 if (on_sig_stack(sp))
495 goto out;
496
ths0da46a62007-10-20 20:23:07 +0000497 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000498 if (ss.ss_flags != TARGET_SS_DISABLE
499 && ss.ss_flags != TARGET_SS_ONSTACK
500 && ss.ss_flags != 0)
501 goto out;
502
503 if (ss.ss_flags == TARGET_SS_DISABLE) {
504 ss.ss_size = 0;
505 ss.ss_sp = 0;
506 } else {
ths0da46a62007-10-20 20:23:07 +0000507 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000508 if (ss.ss_size < MINSIGSTKSZ)
509 goto out;
510 }
511
512 target_sigaltstack_used.ss_sp = ss.ss_sp;
513 target_sigaltstack_used.ss_size = ss.ss_size;
514 }
515
bellard579a97f2007-11-11 14:26:47 +0000516 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000517 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000518 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000519 goto out;
thsa04e1342007-09-27 13:57:58 +0000520 }
521
522 ret = 0;
523out:
524 return ret;
525}
526
ths0da46a62007-10-20 20:23:07 +0000527/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000528int do_sigaction(int sig, const struct target_sigaction *act,
529 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000530{
pbrook624f7972008-05-31 16:11:38 +0000531 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000532 struct sigaction act1;
533 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000534 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000535
ths2a913eb2008-11-27 15:46:25 +0000536 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000537 return -EINVAL;
538 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000539#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000540 fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
bellard66fb9762003-03-23 01:06:05 +0000541 sig, (int)act, (int)oact);
542#endif
543 if (oact) {
pbrook624f7972008-05-31 16:11:38 +0000544 oact->_sa_handler = tswapl(k->_sa_handler);
545 oact->sa_flags = tswapl(k->sa_flags);
ths388bb212007-05-13 13:58:00 +0000546#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000547 oact->sa_restorer = tswapl(k->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000548#endif
pbrook624f7972008-05-31 16:11:38 +0000549 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000550 }
551 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000552 /* FIXME: This is not threadsafe. */
553 k->_sa_handler = tswapl(act->_sa_handler);
554 k->sa_flags = tswapl(act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000555#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000556 k->sa_restorer = tswapl(act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000557#endif
pbrook624f7972008-05-31 16:11:38 +0000558 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000559
560 /* we update the host linux signal state */
561 host_sig = target_to_host_signal(sig);
562 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
563 sigfillset(&act1.sa_mask);
564 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000565 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000566 act1.sa_flags |= SA_RESTART;
567 /* NOTE: it is important to update the host kernel signal
568 ignore state to avoid getting unexpected interrupted
569 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000570 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000571 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000572 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000573 if (fatal_signal (sig))
574 act1.sa_sigaction = host_signal_handler;
575 else
576 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000577 } else {
578 act1.sa_sigaction = host_signal_handler;
579 }
ths0da46a62007-10-20 20:23:07 +0000580 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000581 }
bellard66fb9762003-03-23 01:06:05 +0000582 }
ths0da46a62007-10-20 20:23:07 +0000583 return ret;
bellard66fb9762003-03-23 01:06:05 +0000584}
bellard31e31b82003-02-18 22:55:36 +0000585
ths5fafdf22007-09-16 21:08:06 +0000586static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
bellard43fff232003-07-09 19:31:39 +0000587 const target_siginfo_t *info)
588{
589 tswap_siginfo(tinfo, info);
590 return 0;
591}
592
thsc3b5bc82007-12-02 06:31:25 +0000593static inline int current_exec_domain_sig(int sig)
594{
595 return /* current->exec_domain && current->exec_domain->signal_invmap
596 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
597}
598
bellard459a4012007-11-11 19:45:10 +0000599#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000600
601/* from the Linux kernel */
602
603struct target_fpreg {
604 uint16_t significand[4];
605 uint16_t exponent;
606};
607
608struct target_fpxreg {
609 uint16_t significand[4];
610 uint16_t exponent;
611 uint16_t padding[3];
612};
613
614struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000615 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000616};
617
618struct target_fpstate {
619 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000620 abi_ulong cw;
621 abi_ulong sw;
622 abi_ulong tag;
623 abi_ulong ipoff;
624 abi_ulong cssel;
625 abi_ulong dataoff;
626 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000627 struct target_fpreg _st[8];
628 uint16_t status;
629 uint16_t magic; /* 0xffff = regular FPU data only */
630
631 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000632 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
633 abi_ulong mxcsr;
634 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000635 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
636 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000637 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000638};
639
640#define X86_FXSR_MAGIC 0x0000
641
642struct target_sigcontext {
643 uint16_t gs, __gsh;
644 uint16_t fs, __fsh;
645 uint16_t es, __esh;
646 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000647 abi_ulong edi;
648 abi_ulong esi;
649 abi_ulong ebp;
650 abi_ulong esp;
651 abi_ulong ebx;
652 abi_ulong edx;
653 abi_ulong ecx;
654 abi_ulong eax;
655 abi_ulong trapno;
656 abi_ulong err;
657 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000658 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000659 abi_ulong eflags;
660 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000661 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000662 abi_ulong fpstate; /* pointer */
663 abi_ulong oldmask;
664 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000665};
666
bellard66fb9762003-03-23 01:06:05 +0000667struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000668 abi_ulong tuc_flags;
669 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +0000670 target_stack_t tuc_stack;
671 struct target_sigcontext tuc_mcontext;
672 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000673};
674
675struct sigframe
676{
blueswir1992f48a2007-10-14 16:27:31 +0000677 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000678 int sig;
679 struct target_sigcontext sc;
680 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000681 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000682 char retcode[8];
683};
684
685struct rt_sigframe
686{
blueswir1992f48a2007-10-14 16:27:31 +0000687 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000688 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000689 abi_ulong pinfo;
690 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000691 struct target_siginfo info;
692 struct target_ucontext uc;
693 struct target_fpstate fpstate;
694 char retcode[8];
695};
696
697/*
698 * Set up a signal frame.
699 */
700
bellard66fb9762003-03-23 01:06:05 +0000701/* XXX: save x87 state */
702static int
703setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000704 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000705{
706 int err = 0;
bellard775b58d2007-11-11 16:22:17 +0000707 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000708
bellard579a97f2007-11-11 14:26:47 +0000709 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000710 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
711 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
712 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
713 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000714 err |= __put_user(env->regs[R_EDI], &sc->edi);
715 err |= __put_user(env->regs[R_ESI], &sc->esi);
716 err |= __put_user(env->regs[R_EBP], &sc->ebp);
717 err |= __put_user(env->regs[R_ESP], &sc->esp);
718 err |= __put_user(env->regs[R_EBX], &sc->ebx);
719 err |= __put_user(env->regs[R_EDX], &sc->edx);
720 err |= __put_user(env->regs[R_ECX], &sc->ecx);
721 err |= __put_user(env->regs[R_EAX], &sc->eax);
bellard66099dd2003-05-08 15:34:02 +0000722 err |= __put_user(env->exception_index, &sc->trapno);
723 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000724 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000725 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000726 err |= __put_user(env->eflags, &sc->eflags);
727 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000728 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000729
bellard28be6232007-11-11 22:23:38 +0000730 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000731 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000732 magic = 0xffff;
733 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000734 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000735
bellard66fb9762003-03-23 01:06:05 +0000736 /* non-iBCS2 extensions.. */
737 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000738 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000739 return err;
740}
741
742/*
743 * Determine which stack to use..
744 */
745
bellard579a97f2007-11-11 14:26:47 +0000746static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000747get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000748{
749 unsigned long esp;
750
751 /* Default to using normal stack */
752 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000753 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000754 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000755 if (sas_ss_flags(esp) == 0)
756 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
757 }
bellard66fb9762003-03-23 01:06:05 +0000758
759 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000760 else
bellarda52c7572003-06-21 13:14:12 +0000761 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000762 !(ka->sa_flags & TARGET_SA_RESTORER) &&
763 ka->sa_restorer) {
764 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000765 }
bellard579a97f2007-11-11 14:26:47 +0000766 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000767}
768
bellard579a97f2007-11-11 14:26:47 +0000769/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000770static void setup_frame(int sig, struct target_sigaction *ka,
bellard66fb9762003-03-23 01:06:05 +0000771 target_sigset_t *set, CPUX86State *env)
772{
bellard579a97f2007-11-11 14:26:47 +0000773 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000774 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000775 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000776
bellard579a97f2007-11-11 14:26:47 +0000777 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000778
bellard579a97f2007-11-11 14:26:47 +0000779 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000780 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000781
thsc3b5bc82007-12-02 06:31:25 +0000782 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000783 &frame->sig);
784 if (err)
785 goto give_sigsegv;
786
bellard28be6232007-11-11 22:23:38 +0000787 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
788 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000789 if (err)
790 goto give_sigsegv;
791
bellard92319442004-06-19 16:58:13 +0000792 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
793 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
794 goto give_sigsegv;
795 }
bellard66fb9762003-03-23 01:06:05 +0000796
797 /* Set up to return from userspace. If provided, use a stub
798 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000799 if (ka->sa_flags & TARGET_SA_RESTORER) {
800 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000801 } else {
bellard775b58d2007-11-11 16:22:17 +0000802 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000803 abi_ulong retcode_addr;
804 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
805 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000806 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000807 val16 = 0xb858;
808 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000809 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000810 val16 = 0x80cd;
811 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000812 }
813
814 if (err)
815 goto give_sigsegv;
816
817 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000818 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000819 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000820
821 cpu_x86_load_seg(env, R_DS, __USER_DS);
822 cpu_x86_load_seg(env, R_ES, __USER_DS);
823 cpu_x86_load_seg(env, R_SS, __USER_DS);
824 cpu_x86_load_seg(env, R_CS, __USER_CS);
825 env->eflags &= ~TF_MASK;
826
bellard579a97f2007-11-11 14:26:47 +0000827 unlock_user_struct(frame, frame_addr, 1);
828
bellard66fb9762003-03-23 01:06:05 +0000829 return;
830
831give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000832 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000833 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000834 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000835 force_sig(TARGET_SIGSEGV /* , current */);
836}
837
bellard579a97f2007-11-11 14:26:47 +0000838/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000839static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard9de5e442003-03-23 16:49:39 +0000840 target_siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +0000841 target_sigset_t *set, CPUX86State *env)
842{
bellard28be6232007-11-11 22:23:38 +0000843 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000844 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000845 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000846
bellard579a97f2007-11-11 14:26:47 +0000847 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000848
bellard579a97f2007-11-11 14:26:47 +0000849 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000850 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000851
thsc3b5bc82007-12-02 06:31:25 +0000852 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000853 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000854 addr = frame_addr + offsetof(struct rt_sigframe, info);
855 err |= __put_user(addr, &frame->pinfo);
856 addr = frame_addr + offsetof(struct rt_sigframe, uc);
857 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000858 err |= copy_siginfo_to_user(&frame->info, info);
859 if (err)
860 goto give_sigsegv;
861
862 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000863 err |= __put_user(0, &frame->uc.tuc_flags);
864 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000865 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000866 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000867 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000868 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000869 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000870 &frame->uc.tuc_stack.ss_size);
871 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000872 env, set->sig[0],
873 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000874 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000875 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000876 goto give_sigsegv;
877 }
bellard66fb9762003-03-23 01:06:05 +0000878
879 /* Set up to return from userspace. If provided, use a stub
880 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000881 if (ka->sa_flags & TARGET_SA_RESTORER) {
882 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000883 } else {
bellard775b58d2007-11-11 16:22:17 +0000884 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000885 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
886 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000887 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000888 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000889 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000890 val16 = 0x80cd;
891 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000892 }
893
894 if (err)
895 goto give_sigsegv;
896
897 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000898 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000899 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000900
901 cpu_x86_load_seg(env, R_DS, __USER_DS);
902 cpu_x86_load_seg(env, R_ES, __USER_DS);
903 cpu_x86_load_seg(env, R_SS, __USER_DS);
904 cpu_x86_load_seg(env, R_CS, __USER_CS);
905 env->eflags &= ~TF_MASK;
906
bellard579a97f2007-11-11 14:26:47 +0000907 unlock_user_struct(frame, frame_addr, 1);
908
bellard66fb9762003-03-23 01:06:05 +0000909 return;
910
911give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000912 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000913 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000914 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000915 force_sig(TARGET_SIGSEGV /* , current */);
916}
917
918static int
919restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
920{
921 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000922 abi_ulong fpstate_addr;
923 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000924
bellard28be6232007-11-11 22:23:38 +0000925 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
926 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
927 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
928 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +0000929
bellard28be6232007-11-11 22:23:38 +0000930 env->regs[R_EDI] = tswapl(sc->edi);
931 env->regs[R_ESI] = tswapl(sc->esi);
932 env->regs[R_EBP] = tswapl(sc->ebp);
933 env->regs[R_ESP] = tswapl(sc->esp);
934 env->regs[R_EBX] = tswapl(sc->ebx);
935 env->regs[R_EDX] = tswapl(sc->edx);
936 env->regs[R_ECX] = tswapl(sc->ecx);
937 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +0000938
939 cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
940 cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +0000941
bellard28be6232007-11-11 22:23:38 +0000942 tmpflags = tswapl(sc->eflags);
943 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
944 // regs->orig_eax = -1; /* disable syscall checks */
945
946 fpstate_addr = tswapl(sc->fpstate);
947 if (fpstate_addr != 0) {
948 if (!access_ok(VERIFY_READ, fpstate_addr,
949 sizeof(struct target_fpstate)))
950 goto badframe;
951 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000952 }
953
bellard28be6232007-11-11 22:23:38 +0000954 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +0000955 return err;
bellard66fb9762003-03-23 01:06:05 +0000956badframe:
957 return 1;
bellard66fb9762003-03-23 01:06:05 +0000958}
959
960long do_sigreturn(CPUX86State *env)
961{
bellard579a97f2007-11-11 14:26:47 +0000962 struct sigframe *frame;
963 abi_ulong frame_addr = env->regs[R_ESP] - 8;
bellard66fb9762003-03-23 01:06:05 +0000964 target_sigset_t target_set;
965 sigset_t set;
966 int eax, i;
967
bellard447db212003-05-10 15:10:36 +0000968#if defined(DEBUG_SIGNAL)
969 fprintf(stderr, "do_sigreturn\n");
970#endif
bellard579a97f2007-11-11 14:26:47 +0000971 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
972 goto badframe;
bellard66fb9762003-03-23 01:06:05 +0000973 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +0000974 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
975 goto badframe;
976 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
977 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
978 goto badframe;
979 }
bellard66fb9762003-03-23 01:06:05 +0000980
bellard92319442004-06-19 16:58:13 +0000981 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +0000982 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +0000983
bellard66fb9762003-03-23 01:06:05 +0000984 /* restore registers */
985 if (restore_sigcontext(env, &frame->sc, &eax))
986 goto badframe;
bellard579a97f2007-11-11 14:26:47 +0000987 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +0000988 return eax;
989
990badframe:
bellard579a97f2007-11-11 14:26:47 +0000991 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +0000992 force_sig(TARGET_SIGSEGV);
993 return 0;
994}
995
996long do_rt_sigreturn(CPUX86State *env)
997{
bellard28be6232007-11-11 22:23:38 +0000998 abi_ulong frame_addr;
999 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001000 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001001 int eax;
1002
bellard28be6232007-11-11 22:23:38 +00001003 frame_addr = env->regs[R_ESP] - 4;
1004 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1005 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001006 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +00001007 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001008
bellardb8076a72005-04-07 22:20:31 +00001009 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001010 goto badframe;
1011
bellard28be6232007-11-11 22:23:38 +00001012 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1013 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001014 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001015
bellard28be6232007-11-11 22:23:38 +00001016 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001017 return eax;
1018
1019badframe:
bellard28be6232007-11-11 22:23:38 +00001020 unlock_user_struct(frame, frame_addr, 0);
1021 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001022 return 0;
1023}
1024
bellard43fff232003-07-09 19:31:39 +00001025#elif defined(TARGET_ARM)
1026
1027struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001028 abi_ulong trap_no;
1029 abi_ulong error_code;
1030 abi_ulong oldmask;
1031 abi_ulong arm_r0;
1032 abi_ulong arm_r1;
1033 abi_ulong arm_r2;
1034 abi_ulong arm_r3;
1035 abi_ulong arm_r4;
1036 abi_ulong arm_r5;
1037 abi_ulong arm_r6;
1038 abi_ulong arm_r7;
1039 abi_ulong arm_r8;
1040 abi_ulong arm_r9;
1041 abi_ulong arm_r10;
1042 abi_ulong arm_fp;
1043 abi_ulong arm_ip;
1044 abi_ulong arm_sp;
1045 abi_ulong arm_lr;
1046 abi_ulong arm_pc;
1047 abi_ulong arm_cpsr;
1048 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001049};
1050
pbrooka745ec62008-05-06 15:36:17 +00001051struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001052 abi_ulong tuc_flags;
1053 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +00001054 target_stack_t tuc_stack;
1055 struct target_sigcontext tuc_mcontext;
1056 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001057};
1058
pbrooka745ec62008-05-06 15:36:17 +00001059struct target_ucontext_v2 {
1060 abi_ulong tuc_flags;
1061 abi_ulong tuc_link;
1062 target_stack_t tuc_stack;
1063 struct target_sigcontext tuc_mcontext;
1064 target_sigset_t tuc_sigmask; /* mask last for extensibility */
1065 char __unused[128 - sizeof(sigset_t)];
1066 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1067};
1068
pbrooka8c33202008-05-07 23:22:46 +00001069struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001070{
1071 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001072 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1073 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001074};
1075
pbrooka8c33202008-05-07 23:22:46 +00001076struct sigframe_v2
1077{
1078 struct target_ucontext_v2 uc;
1079 abi_ulong retcode;
1080};
1081
pbrooka745ec62008-05-06 15:36:17 +00001082struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001083{
bellardf8b0aa22007-11-11 23:03:42 +00001084 abi_ulong pinfo;
1085 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001086 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001087 struct target_ucontext_v1 uc;
1088 abi_ulong retcode;
1089};
1090
1091struct rt_sigframe_v2
1092{
1093 struct target_siginfo info;
1094 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001095 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001096};
1097
1098#define TARGET_CONFIG_CPU_32 1
1099
1100/*
1101 * For ARM syscalls, we encode the syscall number into the instruction.
1102 */
1103#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1104#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1105
1106/*
1107 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1108 * need two 16-bit instructions.
1109 */
1110#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1111#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1112
blueswir1992f48a2007-10-14 16:27:31 +00001113static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001114 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1115 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1116};
1117
1118
bellard43fff232003-07-09 19:31:39 +00001119#define __get_user_error(x,p,e) __get_user(x, p)
1120
1121static inline int valid_user_regs(CPUState *regs)
1122{
1123 return 1;
1124}
1125
pbrooka8c33202008-05-07 23:22:46 +00001126static void
bellard43fff232003-07-09 19:31:39 +00001127setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
bellardf8b0aa22007-11-11 23:03:42 +00001128 CPUState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001129{
pbrooka8c33202008-05-07 23:22:46 +00001130 __put_user(env->regs[0], &sc->arm_r0);
1131 __put_user(env->regs[1], &sc->arm_r1);
1132 __put_user(env->regs[2], &sc->arm_r2);
1133 __put_user(env->regs[3], &sc->arm_r3);
1134 __put_user(env->regs[4], &sc->arm_r4);
1135 __put_user(env->regs[5], &sc->arm_r5);
1136 __put_user(env->regs[6], &sc->arm_r6);
1137 __put_user(env->regs[7], &sc->arm_r7);
1138 __put_user(env->regs[8], &sc->arm_r8);
1139 __put_user(env->regs[9], &sc->arm_r9);
1140 __put_user(env->regs[10], &sc->arm_r10);
1141 __put_user(env->regs[11], &sc->arm_fp);
1142 __put_user(env->regs[12], &sc->arm_ip);
1143 __put_user(env->regs[13], &sc->arm_sp);
1144 __put_user(env->regs[14], &sc->arm_lr);
1145 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001146#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001147 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001148#endif
1149
pbrooka8c33202008-05-07 23:22:46 +00001150 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1151 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1152 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1153 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001154}
1155
bellard579a97f2007-11-11 14:26:47 +00001156static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00001157get_sigframe(struct target_sigaction *ka, CPUState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001158{
1159 unsigned long sp = regs->regs[13];
1160
bellard43fff232003-07-09 19:31:39 +00001161 /*
1162 * This is the X/Open sanctioned signal stack switching.
1163 */
pbrook624f7972008-05-31 16:11:38 +00001164 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001165 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001166 /*
1167 * ATPCS B01 mandates 8-byte alignment
1168 */
bellard579a97f2007-11-11 14:26:47 +00001169 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001170}
1171
1172static int
pbrook624f7972008-05-31 16:11:38 +00001173setup_return(CPUState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001174 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001175{
pbrook624f7972008-05-31 16:11:38 +00001176 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001177 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001178 int thumb = handler & 1;
bellard43fff232003-07-09 19:31:39 +00001179
pbrook624f7972008-05-31 16:11:38 +00001180 if (ka->sa_flags & TARGET_SA_RESTORER) {
1181 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001182 } else {
1183 unsigned int idx = thumb;
1184
pbrook624f7972008-05-31 16:11:38 +00001185 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001186 idx += 2;
1187
1188 if (__put_user(retcodes[idx], rc))
1189 return 1;
1190#if 0
blueswir1992f48a2007-10-14 16:27:31 +00001191 flush_icache_range((abi_ulong)rc,
1192 (abi_ulong)(rc + 1));
bellard43fff232003-07-09 19:31:39 +00001193#endif
bellardf8b0aa22007-11-11 23:03:42 +00001194 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001195 }
1196
1197 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001198 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001199 env->regs[14] = retcode;
1200 env->regs[15] = handler & (thumb ? ~1 : ~3);
pbrook75b680e2008-03-21 16:07:30 +00001201 env->thumb = thumb;
bellard43fff232003-07-09 19:31:39 +00001202
bellardb5ff1b32005-11-26 10:38:39 +00001203#if 0
bellard43fff232003-07-09 19:31:39 +00001204#ifdef TARGET_CONFIG_CPU_32
1205 env->cpsr = cpsr;
1206#endif
bellardb5ff1b32005-11-26 10:38:39 +00001207#endif
bellard43fff232003-07-09 19:31:39 +00001208
1209 return 0;
1210}
1211
pbrooka8c33202008-05-07 23:22:46 +00001212static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
1213 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001214{
pbrooka8c33202008-05-07 23:22:46 +00001215 struct target_sigaltstack stack;
1216 int i;
1217
1218 /* Clear all the bits of the ucontext we don't use. */
1219 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1220
1221 memset(&stack, 0, sizeof(stack));
1222 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1223 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1224 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1225 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1226
1227 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
1228 /* FIXME: Save coprocessor signal frame. */
1229 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1230 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1231 }
1232}
1233
1234/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001235static void setup_frame_v1(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001236 target_sigset_t *set, CPUState *regs)
1237{
1238 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001239 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001240 int i;
bellard43fff232003-07-09 19:31:39 +00001241
bellard579a97f2007-11-11 14:26:47 +00001242 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1243 return;
1244
pbrooka8c33202008-05-07 23:22:46 +00001245 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001246
bellard92319442004-06-19 16:58:13 +00001247 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1248 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001249 goto end;
bellard43fff232003-07-09 19:31:39 +00001250 }
1251
pbrooka8c33202008-05-07 23:22:46 +00001252 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1253 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001254
1255end:
1256 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001257}
1258
pbrook624f7972008-05-31 16:11:38 +00001259static void setup_frame_v2(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001260 target_sigset_t *set, CPUState *regs)
1261{
1262 struct sigframe_v2 *frame;
1263 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1264
1265 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1266 return;
1267
1268 setup_sigframe_v2(&frame->uc, set, regs);
1269
1270 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1271 frame_addr + offsetof(struct sigframe_v2, retcode));
1272
1273 unlock_user_struct(frame, frame_addr, 1);
1274}
1275
pbrook624f7972008-05-31 16:11:38 +00001276static void setup_frame(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001277 target_sigset_t *set, CPUState *regs)
1278{
1279 if (get_osversion() >= 0x020612) {
1280 setup_frame_v2(usig, ka, set, regs);
1281 } else {
1282 setup_frame_v1(usig, ka, set, regs);
1283 }
bellard43fff232003-07-09 19:31:39 +00001284}
1285
bellard579a97f2007-11-11 14:26:47 +00001286/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001287static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001288 target_siginfo_t *info,
1289 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001290{
pbrooka745ec62008-05-06 15:36:17 +00001291 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001292 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001293 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001294 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001295 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001296
bellard579a97f2007-11-11 14:26:47 +00001297 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001298 return /* 1 */;
1299
pbrooka745ec62008-05-06 15:36:17 +00001300 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001301 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001302 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001303 __put_user(uc_addr, &frame->puc);
1304 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001305
1306 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001307 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001308
thsa04e1342007-09-27 13:57:58 +00001309 memset(&stack, 0, sizeof(stack));
1310 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1311 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1312 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001313 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001314
pbrooka8c33202008-05-07 23:22:46 +00001315 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001316 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001317 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001318 goto end;
bellard92319442004-06-19 16:58:13 +00001319 }
bellard43fff232003-07-09 19:31:39 +00001320
pbrooka8c33202008-05-07 23:22:46 +00001321 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1322 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001323
pbrooka8c33202008-05-07 23:22:46 +00001324 env->regs[1] = info_addr;
1325 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001326
1327end:
1328 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001329}
1330
pbrook624f7972008-05-31 16:11:38 +00001331static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001332 target_siginfo_t *info,
1333 target_sigset_t *set, CPUState *env)
1334{
1335 struct rt_sigframe_v2 *frame;
1336 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001337 abi_ulong info_addr, uc_addr;
1338
1339 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1340 return /* 1 */;
1341
1342 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1343 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001344 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001345
pbrooka8c33202008-05-07 23:22:46 +00001346 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001347
pbrooka8c33202008-05-07 23:22:46 +00001348 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1349 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001350
pbrooka8c33202008-05-07 23:22:46 +00001351 env->regs[1] = info_addr;
1352 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001353
bellard579a97f2007-11-11 14:26:47 +00001354 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001355}
1356
pbrook624f7972008-05-31 16:11:38 +00001357static void setup_rt_frame(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001358 target_siginfo_t *info,
1359 target_sigset_t *set, CPUState *env)
1360{
1361 if (get_osversion() >= 0x020612) {
1362 setup_rt_frame_v2(usig, ka, info, set, env);
1363 } else {
1364 setup_rt_frame_v1(usig, ka, info, set, env);
1365 }
1366}
1367
bellard43fff232003-07-09 19:31:39 +00001368static int
1369restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
1370{
1371 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001372 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001373
1374 __get_user_error(env->regs[0], &sc->arm_r0, err);
1375 __get_user_error(env->regs[1], &sc->arm_r1, err);
1376 __get_user_error(env->regs[2], &sc->arm_r2, err);
1377 __get_user_error(env->regs[3], &sc->arm_r3, err);
1378 __get_user_error(env->regs[4], &sc->arm_r4, err);
1379 __get_user_error(env->regs[5], &sc->arm_r5, err);
1380 __get_user_error(env->regs[6], &sc->arm_r6, err);
1381 __get_user_error(env->regs[7], &sc->arm_r7, err);
1382 __get_user_error(env->regs[8], &sc->arm_r8, err);
1383 __get_user_error(env->regs[9], &sc->arm_r9, err);
1384 __get_user_error(env->regs[10], &sc->arm_r10, err);
1385 __get_user_error(env->regs[11], &sc->arm_fp, err);
1386 __get_user_error(env->regs[12], &sc->arm_ip, err);
1387 __get_user_error(env->regs[13], &sc->arm_sp, err);
1388 __get_user_error(env->regs[14], &sc->arm_lr, err);
1389 __get_user_error(env->regs[15], &sc->arm_pc, err);
1390#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001391 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001392 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001393#endif
1394
1395 err |= !valid_user_regs(env);
1396
1397 return err;
1398}
1399
pbrooka8c33202008-05-07 23:22:46 +00001400long do_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001401{
bellardf8b0aa22007-11-11 23:03:42 +00001402 abi_ulong frame_addr;
pbrooka8c33202008-05-07 23:22:46 +00001403 struct sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001404 target_sigset_t set;
1405 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001406 int i;
bellard43fff232003-07-09 19:31:39 +00001407
1408 /*
1409 * Since we stacked the signal on a 64-bit boundary,
1410 * then 'sp' should be word aligned here. If it's
1411 * not, then the user is trying to mess with us.
1412 */
1413 if (env->regs[13] & 7)
1414 goto badframe;
1415
bellardf8b0aa22007-11-11 23:03:42 +00001416 frame_addr = env->regs[13];
1417 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1418 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001419
bellard92319442004-06-19 16:58:13 +00001420 if (__get_user(set.sig[0], &frame->sc.oldmask))
1421 goto badframe;
1422 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1423 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1424 goto badframe;
1425 }
bellard43fff232003-07-09 19:31:39 +00001426
bellard92319442004-06-19 16:58:13 +00001427 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001428 sigprocmask(SIG_SETMASK, &host_set, NULL);
1429
1430 if (restore_sigcontext(env, &frame->sc))
1431 goto badframe;
1432
1433#if 0
1434 /* Send SIGTRAP if we're single-stepping */
1435 if (ptrace_cancel_bpt(current))
1436 send_sig(SIGTRAP, current, 1);
1437#endif
bellardf8b0aa22007-11-11 23:03:42 +00001438 unlock_user_struct(frame, frame_addr, 0);
1439 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001440
1441badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001442 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001443 force_sig(SIGSEGV /* , current */);
1444 return 0;
1445}
1446
pbrooka8c33202008-05-07 23:22:46 +00001447static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr,
1448 struct target_ucontext_v2 *uc)
1449{
1450 sigset_t host_set;
1451
1452 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1453 sigprocmask(SIG_SETMASK, &host_set, NULL);
1454
1455 if (restore_sigcontext(env, &uc->tuc_mcontext))
1456 return 1;
1457
1458 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1459 return 1;
1460
1461#if 0
1462 /* Send SIGTRAP if we're single-stepping */
1463 if (ptrace_cancel_bpt(current))
1464 send_sig(SIGTRAP, current, 1);
1465#endif
1466
1467 return 0;
1468}
1469
1470long do_sigreturn_v2(CPUState *env)
1471{
1472 abi_ulong frame_addr;
1473 struct sigframe_v2 *frame;
1474
1475 /*
1476 * Since we stacked the signal on a 64-bit boundary,
1477 * then 'sp' should be word aligned here. If it's
1478 * not, then the user is trying to mess with us.
1479 */
1480 if (env->regs[13] & 7)
1481 goto badframe;
1482
1483 frame_addr = env->regs[13];
1484 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1485 goto badframe;
1486
1487 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1488 goto badframe;
1489
1490 unlock_user_struct(frame, frame_addr, 0);
1491 return env->regs[0];
1492
1493badframe:
1494 unlock_user_struct(frame, frame_addr, 0);
1495 force_sig(SIGSEGV /* , current */);
1496 return 0;
1497}
1498
1499long do_sigreturn(CPUState *env)
1500{
1501 if (get_osversion() >= 0x020612) {
1502 return do_sigreturn_v2(env);
1503 } else {
1504 return do_sigreturn_v1(env);
1505 }
1506}
1507
pbrooka745ec62008-05-06 15:36:17 +00001508long do_rt_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001509{
bellardf8b0aa22007-11-11 23:03:42 +00001510 abi_ulong frame_addr;
pbrooka745ec62008-05-06 15:36:17 +00001511 struct rt_sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001512 sigset_t host_set;
1513
1514 /*
1515 * Since we stacked the signal on a 64-bit boundary,
1516 * then 'sp' should be word aligned here. If it's
1517 * not, then the user is trying to mess with us.
1518 */
1519 if (env->regs[13] & 7)
1520 goto badframe;
1521
bellardf8b0aa22007-11-11 23:03:42 +00001522 frame_addr = env->regs[13];
1523 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1524 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001525
bellardb8076a72005-04-07 22:20:31 +00001526 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00001527 sigprocmask(SIG_SETMASK, &host_set, NULL);
1528
bellardb8076a72005-04-07 22:20:31 +00001529 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00001530 goto badframe;
1531
pbrooka745ec62008-05-06 15:36:17 +00001532 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 +00001533 goto badframe;
1534
bellard43fff232003-07-09 19:31:39 +00001535#if 0
1536 /* Send SIGTRAP if we're single-stepping */
1537 if (ptrace_cancel_bpt(current))
1538 send_sig(SIGTRAP, current, 1);
1539#endif
bellardf8b0aa22007-11-11 23:03:42 +00001540 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001541 return env->regs[0];
1542
1543badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001544 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001545 force_sig(SIGSEGV /* , current */);
1546 return 0;
1547}
1548
pbrooka745ec62008-05-06 15:36:17 +00001549long do_rt_sigreturn_v2(CPUState *env)
1550{
1551 abi_ulong frame_addr;
1552 struct rt_sigframe_v2 *frame;
pbrooka745ec62008-05-06 15:36:17 +00001553
1554 /*
1555 * Since we stacked the signal on a 64-bit boundary,
1556 * then 'sp' should be word aligned here. If it's
1557 * not, then the user is trying to mess with us.
1558 */
1559 if (env->regs[13] & 7)
1560 goto badframe;
1561
1562 frame_addr = env->regs[13];
1563 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1564 goto badframe;
1565
pbrooka8c33202008-05-07 23:22:46 +00001566 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1567 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00001568
pbrooka745ec62008-05-06 15:36:17 +00001569 unlock_user_struct(frame, frame_addr, 0);
1570 return env->regs[0];
1571
1572badframe:
1573 unlock_user_struct(frame, frame_addr, 0);
1574 force_sig(SIGSEGV /* , current */);
1575 return 0;
1576}
1577
1578long do_rt_sigreturn(CPUState *env)
1579{
1580 if (get_osversion() >= 0x020612) {
1581 return do_rt_sigreturn_v2(env);
1582 } else {
1583 return do_rt_sigreturn_v1(env);
1584 }
1585}
1586
bellard6d5e2162004-09-30 22:04:13 +00001587#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00001588
bellard6d5e2162004-09-30 22:04:13 +00001589#define __SUNOS_MAXWIN 31
1590
1591/* This is what SunOS does, so shall I. */
1592struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001593 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00001594
blueswir1992f48a2007-10-14 16:27:31 +00001595 abi_ulong sigc_mask; /* sigmask to restore */
1596 abi_ulong sigc_sp; /* stack pointer */
1597 abi_ulong sigc_pc; /* program counter */
1598 abi_ulong sigc_npc; /* next program counter */
1599 abi_ulong sigc_psr; /* for condition codes etc */
1600 abi_ulong sigc_g1; /* User uses these two registers */
1601 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00001602
1603 /* Now comes information regarding the users window set
1604 * at the time of the signal.
1605 */
blueswir1992f48a2007-10-14 16:27:31 +00001606 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00001607
1608 /* stack ptrs for each regwin buf */
1609 char *sigc_spbuf[__SUNOS_MAXWIN];
1610
1611 /* Windows to restore after signal */
1612 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001613 abi_ulong locals[8];
1614 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00001615 } sigc_wbuf[__SUNOS_MAXWIN];
1616};
1617/* A Sparc stack frame */
1618struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00001619 abi_ulong locals[8];
1620 abi_ulong ins[6];
bellard6d5e2162004-09-30 22:04:13 +00001621 struct sparc_stackf *fp;
blueswir1992f48a2007-10-14 16:27:31 +00001622 abi_ulong callers_pc;
bellard6d5e2162004-09-30 22:04:13 +00001623 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00001624 abi_ulong xargs[6];
1625 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00001626};
1627
1628typedef struct {
1629 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001630 abi_ulong psr;
1631 abi_ulong pc;
1632 abi_ulong npc;
1633 abi_ulong y;
1634 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00001635 } si_regs;
1636 int si_mask;
1637} __siginfo_t;
1638
1639typedef struct {
1640 unsigned long si_float_regs [32];
1641 unsigned long si_fsr;
1642 unsigned long si_fpqdepth;
1643 struct {
1644 unsigned long *insn_addr;
1645 unsigned long insn;
1646 } si_fpqueue [16];
bellard74ccb342006-07-18 21:23:34 +00001647} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00001648
1649
1650struct target_signal_frame {
1651 struct sparc_stackf ss;
1652 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00001653 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00001654 abi_ulong insns[2] __attribute__ ((aligned (8)));
1655 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
1656 abi_ulong extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001657 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001658};
1659struct target_rt_signal_frame {
1660 struct sparc_stackf ss;
1661 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00001662 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00001663 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00001664 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00001665 unsigned int insns[2];
1666 stack_t stack;
1667 unsigned int extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001668 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001669};
1670
bellarde80cfcf2004-12-19 23:18:01 +00001671#define UREG_O0 16
1672#define UREG_O6 22
1673#define UREG_I0 0
1674#define UREG_I1 1
1675#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00001676#define UREG_I3 3
1677#define UREG_I4 4
1678#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00001679#define UREG_I6 6
1680#define UREG_I7 7
1681#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00001682#define UREG_FP UREG_I6
1683#define UREG_SP UREG_O6
1684
pbrook624f7972008-05-31 16:11:38 +00001685static inline abi_ulong get_sigframe(struct target_sigaction *sa,
bellard459a4012007-11-11 19:45:10 +00001686 CPUState *env, unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00001687{
bellard459a4012007-11-11 19:45:10 +00001688 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00001689
1690 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00001691
1692 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00001693 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00001694 if (!on_sig_stack(sp)
1695 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
1696 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00001697 }
bellard459a4012007-11-11 19:45:10 +00001698 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00001699}
1700
1701static int
blueswir1992f48a2007-10-14 16:27:31 +00001702setup___siginfo(__siginfo_t *si, CPUState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00001703{
1704 int err = 0, i;
1705
bellard6d5e2162004-09-30 22:04:13 +00001706 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00001707 err |= __put_user(env->pc, &si->si_regs.pc);
1708 err |= __put_user(env->npc, &si->si_regs.npc);
1709 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001710 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00001711 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
1712 }
bellarda315a142005-01-30 22:59:18 +00001713 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001714 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00001715 }
bellard6d5e2162004-09-30 22:04:13 +00001716 err |= __put_user(mask, &si->si_mask);
1717 return err;
1718}
bellarde80cfcf2004-12-19 23:18:01 +00001719
bellard80a9d032005-01-03 23:31:27 +00001720#if 0
bellard6d5e2162004-09-30 22:04:13 +00001721static int
1722setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
1723 CPUState *env, unsigned long mask)
1724{
1725 int err = 0;
1726
1727 err |= __put_user(mask, &sc->sigc_mask);
1728 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
1729 err |= __put_user(env->pc, &sc->sigc_pc);
1730 err |= __put_user(env->npc, &sc->sigc_npc);
1731 err |= __put_user(env->psr, &sc->sigc_psr);
1732 err |= __put_user(env->gregs[1], &sc->sigc_g1);
1733 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
1734
1735 return err;
1736}
bellard80a9d032005-01-03 23:31:27 +00001737#endif
bellard6d5e2162004-09-30 22:04:13 +00001738#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
1739
pbrook624f7972008-05-31 16:11:38 +00001740static void setup_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001741 target_sigset_t *set, CPUState *env)
1742{
bellard459a4012007-11-11 19:45:10 +00001743 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001744 struct target_signal_frame *sf;
1745 int sigframe_size, err, i;
1746
1747 /* 1. Make sure everything is clean */
1748 //synchronize_user_stack();
1749
1750 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00001751 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00001752
bellard459a4012007-11-11 19:45:10 +00001753 sf = lock_user(VERIFY_WRITE, sf_addr,
1754 sizeof(struct target_signal_frame), 0);
1755 if (!sf)
1756 goto sigsegv;
1757
bellarde80cfcf2004-12-19 23:18:01 +00001758 //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 +00001759#if 0
1760 if (invalid_frame_pointer(sf, sigframe_size))
1761 goto sigill_and_return;
1762#endif
1763 /* 2. Save the current process state */
1764 err = setup___siginfo(&sf->info, env, set->sig[0]);
1765 err |= __put_user(0, &sf->extra_size);
1766
1767 //err |= save_fpu_state(regs, &sf->fpu_state);
1768 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
1769
1770 err |= __put_user(set->sig[0], &sf->info.si_mask);
1771 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
1772 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
1773 }
1774
bellarda315a142005-01-30 22:59:18 +00001775 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001776 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00001777 }
bellarda315a142005-01-30 22:59:18 +00001778 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001779 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00001780 }
bellard6d5e2162004-09-30 22:04:13 +00001781 if (err)
1782 goto sigsegv;
1783
1784 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00001785 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001786 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00001787 env->regwptr[UREG_I1] = sf_addr +
1788 offsetof(struct target_signal_frame, info);
1789 env->regwptr[UREG_I2] = sf_addr +
1790 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00001791
1792 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00001793 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00001794 env->npc = (env->pc + 4);
1795 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00001796 if (ka->sa_restorer)
1797 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00001798 else {
bellard775b58d2007-11-11 16:22:17 +00001799 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00001800
1801 env->regwptr[UREG_I7] = sf_addr +
1802 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00001803
1804 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00001805 val32 = 0x821020d8;
1806 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00001807
1808 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00001809 val32 = 0x91d02010;
1810 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00001811 if (err)
1812 goto sigsegv;
1813
1814 /* Flush instruction space. */
1815 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00001816 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00001817 }
bellard459a4012007-11-11 19:45:10 +00001818 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001819 return;
bellard459a4012007-11-11 19:45:10 +00001820#if 0
1821sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00001822 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00001823#endif
bellard6d5e2162004-09-30 22:04:13 +00001824sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00001825 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00001826 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001827 force_sig(TARGET_SIGSEGV);
1828}
1829static inline int
bellard74ccb342006-07-18 21:23:34 +00001830restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00001831{
1832 int err;
1833#if 0
1834#ifdef CONFIG_SMP
1835 if (current->flags & PF_USEDFPU)
1836 regs->psr &= ~PSR_EF;
1837#else
1838 if (current == last_task_used_math) {
1839 last_task_used_math = 0;
1840 regs->psr &= ~PSR_EF;
1841 }
1842#endif
1843 current->used_math = 1;
1844 current->flags &= ~PF_USEDFPU;
1845#endif
1846#if 0
1847 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
1848 return -EFAULT;
1849#endif
1850
bellardfafffae2006-10-28 12:09:16 +00001851#if 0
1852 /* XXX: incorrect */
bellard6d5e2162004-09-30 22:04:13 +00001853 err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
1854 (sizeof(unsigned long) * 32));
bellardfafffae2006-10-28 12:09:16 +00001855#endif
bellard6d5e2162004-09-30 22:04:13 +00001856 err |= __get_user(env->fsr, &fpu->si_fsr);
1857#if 0
1858 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
1859 if (current->thread.fpqdepth != 0)
1860 err |= __copy_from_user(&current->thread.fpqueue[0],
1861 &fpu->si_fpqueue[0],
1862 ((sizeof(unsigned long) +
1863 (sizeof(unsigned long *)))*16));
1864#endif
1865 return err;
1866}
1867
1868
pbrook624f7972008-05-31 16:11:38 +00001869static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001870 target_siginfo_t *info,
1871 target_sigset_t *set, CPUState *env)
1872{
1873 fprintf(stderr, "setup_rt_frame: not implemented\n");
1874}
1875
1876long do_sigreturn(CPUState *env)
1877{
bellardf8b0aa22007-11-11 23:03:42 +00001878 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001879 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00001880 uint32_t up_psr, pc, npc;
bellard6d5e2162004-09-30 22:04:13 +00001881 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00001882 sigset_t host_set;
bellardf8b0aa22007-11-11 23:03:42 +00001883 abi_ulong fpu_save_addr;
bellarde80cfcf2004-12-19 23:18:01 +00001884 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00001885
bellardf8b0aa22007-11-11 23:03:42 +00001886 sf_addr = env->regwptr[UREG_FP];
1887 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
1888 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00001889#if 0
bellarde80cfcf2004-12-19 23:18:01 +00001890 fprintf(stderr, "sigreturn\n");
1891 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 +00001892#endif
bellarde80cfcf2004-12-19 23:18:01 +00001893 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00001894
1895 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00001896
bellardf8b0aa22007-11-11 23:03:42 +00001897 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00001898 goto segv_and_exit;
1899
1900 err = __get_user(pc, &sf->info.si_regs.pc);
1901 err |= __get_user(npc, &sf->info.si_regs.npc);
1902
bellard6d5e2162004-09-30 22:04:13 +00001903 if ((pc | npc) & 3)
1904 goto segv_and_exit;
1905
1906 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00001907 err |= __get_user(up_psr, &sf->info.si_regs.psr);
1908
bellard6d5e2162004-09-30 22:04:13 +00001909 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00001910 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
1911 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
1912
1913 env->pc = pc;
1914 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00001915 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001916 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001917 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
1918 }
bellarda315a142005-01-30 22:59:18 +00001919 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001920 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
1921 }
bellard6d5e2162004-09-30 22:04:13 +00001922
bellardf8b0aa22007-11-11 23:03:42 +00001923 err |= __get_user(fpu_save_addr, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001924
bellarde80cfcf2004-12-19 23:18:01 +00001925 //if (fpu_save)
1926 // err |= restore_fpu_state(env, fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001927
1928 /* This is pretty much atomic, no amount locking would prevent
1929 * the races which exist anyways.
1930 */
1931 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00001932 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1933 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
1934 }
1935
1936 target_to_host_sigset_internal(&host_set, &set);
1937 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00001938
1939 if (err)
1940 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00001941 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001942 return env->regwptr[0];
1943
1944segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00001945 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001946 force_sig(TARGET_SIGSEGV);
1947}
1948
1949long do_rt_sigreturn(CPUState *env)
1950{
1951 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00001952 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00001953}
1954
bellard459a4012007-11-11 19:45:10 +00001955#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00001956#define MC_TSTATE 0
1957#define MC_PC 1
1958#define MC_NPC 2
1959#define MC_Y 3
1960#define MC_G1 4
1961#define MC_G2 5
1962#define MC_G3 6
1963#define MC_G4 7
1964#define MC_G5 8
1965#define MC_G6 9
1966#define MC_G7 10
1967#define MC_O0 11
1968#define MC_O1 12
1969#define MC_O2 13
1970#define MC_O3 14
1971#define MC_O4 15
1972#define MC_O5 16
1973#define MC_O6 17
1974#define MC_O7 18
1975#define MC_NGREG 19
1976
blueswir1992f48a2007-10-14 16:27:31 +00001977typedef abi_ulong target_mc_greg_t;
blueswir15bfb56b2007-10-05 17:01:51 +00001978typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
1979
1980struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00001981 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00001982 uint32_t mcfq_insn;
1983};
1984
1985struct target_mc_fpu {
1986 union {
1987 uint32_t sregs[32];
1988 uint64_t dregs[32];
1989 //uint128_t qregs[16];
1990 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00001991 abi_ulong mcfpu_fsr;
1992 abi_ulong mcfpu_fprs;
1993 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00001994 struct target_mc_fq *mcfpu_fq;
1995 unsigned char mcfpu_qcnt;
1996 unsigned char mcfpu_qentsz;
1997 unsigned char mcfpu_enab;
1998};
1999typedef struct target_mc_fpu target_mc_fpu_t;
2000
2001typedef struct {
2002 target_mc_gregset_t mc_gregs;
2003 target_mc_greg_t mc_fp;
2004 target_mc_greg_t mc_i7;
2005 target_mc_fpu_t mc_fpregs;
2006} target_mcontext_t;
2007
2008struct target_ucontext {
2009 struct target_ucontext *uc_link;
blueswir1992f48a2007-10-14 16:27:31 +00002010 abi_ulong uc_flags;
blueswir15bfb56b2007-10-05 17:01:51 +00002011 target_sigset_t uc_sigmask;
2012 target_mcontext_t uc_mcontext;
2013};
2014
2015/* A V9 register window */
2016struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002017 abi_ulong locals[8];
2018 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002019};
2020
2021#define TARGET_STACK_BIAS 2047
2022
2023/* {set, get}context() needed for 64-bit SparcLinux userland. */
2024void sparc64_set_context(CPUSPARCState *env)
2025{
bellard459a4012007-11-11 19:45:10 +00002026 abi_ulong ucp_addr;
2027 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00002028 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002029 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002030 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002031 unsigned char fenab;
2032 int err;
2033 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002034
bellard459a4012007-11-11 19:45:10 +00002035 ucp_addr = env->regwptr[UREG_I0];
2036 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2037 goto do_sigsegv;
blueswir15bfb56b2007-10-05 17:01:51 +00002038 grp = &ucp->uc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002039 err = __get_user(pc, &((*grp)[MC_PC]));
2040 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002041 if (err || ((pc | npc) & 3))
2042 goto do_sigsegv;
2043 if (env->regwptr[UREG_I1]) {
2044 target_sigset_t target_set;
2045 sigset_t set;
2046
2047 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002048 if (__get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002049 goto do_sigsegv;
2050 } else {
bellard459a4012007-11-11 19:45:10 +00002051 abi_ulong *src, *dst;
2052 src = ucp->uc_sigmask.sig;
2053 dst = target_set.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002054 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002055 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002056 err |= __get_user(*dst, src);
blueswir15bfb56b2007-10-05 17:01:51 +00002057 if (err)
2058 goto do_sigsegv;
2059 }
2060 target_to_host_sigset_internal(&set, &target_set);
2061 sigprocmask(SIG_SETMASK, &set, NULL);
2062 }
2063 env->pc = pc;
2064 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002065 err |= __get_user(env->y, &((*grp)[MC_Y]));
2066 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002067 env->asi = (tstate >> 24) & 0xff;
2068 PUT_CCR(env, tstate >> 32);
2069 PUT_CWP64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002070 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2071 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2072 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2073 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2074 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2075 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2076 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2077 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2078 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2079 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2080 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2081 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2082 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2083 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2084 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002085
bellard579a97f2007-11-11 14:26:47 +00002086 err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp));
2087 err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002088
bellard459a4012007-11-11 19:45:10 +00002089 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2090 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2091 abi_ulong) != 0)
2092 goto do_sigsegv;
2093 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2094 abi_ulong) != 0)
2095 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002096 err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
2097 err |= __get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002098 {
2099 uint32_t *src, *dst;
2100 src = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2101 dst = env->fpr;
2102 /* XXX: check that the CPU storage is the same as user context */
2103 for (i = 0; i < 64; i++, dst++, src++)
2104 err |= __get_user(*dst, src);
2105 }
bellard579a97f2007-11-11 14:26:47 +00002106 err |= __get_user(env->fsr,
2107 &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
2108 err |= __get_user(env->gsr,
2109 &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002110 if (err)
2111 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002112 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002113 return;
2114 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002115 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002116 force_sig(SIGSEGV);
2117}
2118
2119void sparc64_get_context(CPUSPARCState *env)
2120{
bellard459a4012007-11-11 19:45:10 +00002121 abi_ulong ucp_addr;
2122 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00002123 target_mc_gregset_t *grp;
2124 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002125 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002126 int err;
2127 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002128 target_sigset_t target_set;
2129 sigset_t set;
2130
bellard459a4012007-11-11 19:45:10 +00002131 ucp_addr = env->regwptr[UREG_I0];
2132 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2133 goto do_sigsegv;
2134
blueswir15bfb56b2007-10-05 17:01:51 +00002135 mcp = &ucp->uc_mcontext;
2136 grp = &mcp->mc_gregs;
2137
2138 /* Skip over the trap instruction, first. */
2139 env->pc = env->npc;
2140 env->npc += 4;
2141
2142 err = 0;
2143
2144 sigprocmask(0, NULL, &set);
2145 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002146 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002147 err |= __put_user(target_set.sig[0],
2148 (abi_ulong *)&ucp->uc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002149 } else {
2150 abi_ulong *src, *dst;
2151 src = target_set.sig;
2152 dst = ucp->uc_sigmask.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002153 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002154 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002155 err |= __put_user(*src, dst);
blueswir15bfb56b2007-10-05 17:01:51 +00002156 if (err)
2157 goto do_sigsegv;
2158 }
2159
bellard459a4012007-11-11 19:45:10 +00002160 /* XXX: tstate must be saved properly */
2161 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002162 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2163 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2164 err |= __put_user(env->y, &((*grp)[MC_Y]));
2165 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2166 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2167 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2168 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2169 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2170 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2171 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2172 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2173 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2174 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2175 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2176 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2177 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2178 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2179 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002180
bellard459a4012007-11-11 19:45:10 +00002181 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2182 fp = i7 = 0;
2183 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2184 abi_ulong) != 0)
2185 goto do_sigsegv;
2186 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2187 abi_ulong) != 0)
2188 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002189 err |= __put_user(fp, &(mcp->mc_fp));
2190 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002191
bellard459a4012007-11-11 19:45:10 +00002192 {
2193 uint32_t *src, *dst;
2194 src = env->fpr;
2195 dst = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2196 /* XXX: check that the CPU storage is the same as user context */
2197 for (i = 0; i < 64; i++, dst++, src++)
2198 err |= __put_user(*src, dst);
2199 }
bellard579a97f2007-11-11 14:26:47 +00002200 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2201 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2202 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002203
2204 if (err)
2205 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002206 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002207 return;
2208 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002209 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002210 force_sig(SIGSEGV);
2211}
2212#endif
thsd26bc212007-11-08 18:05:37 +00002213#elif defined(TARGET_ABI_MIPSN64)
ths540635b2007-09-30 01:58:33 +00002214
2215# warning signal handling not implemented
2216
pbrook624f7972008-05-31 16:11:38 +00002217static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002218 target_sigset_t *set, CPUState *env)
2219{
2220 fprintf(stderr, "setup_frame: not implemented\n");
2221}
2222
pbrook624f7972008-05-31 16:11:38 +00002223static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002224 target_siginfo_t *info,
2225 target_sigset_t *set, CPUState *env)
2226{
2227 fprintf(stderr, "setup_rt_frame: not implemented\n");
2228}
2229
2230long do_sigreturn(CPUState *env)
2231{
2232 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002233 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002234}
2235
2236long do_rt_sigreturn(CPUState *env)
2237{
2238 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002239 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002240}
2241
thsd26bc212007-11-08 18:05:37 +00002242#elif defined(TARGET_ABI_MIPSN32)
ths540635b2007-09-30 01:58:33 +00002243
2244# warning signal handling not implemented
2245
pbrook624f7972008-05-31 16:11:38 +00002246static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002247 target_sigset_t *set, CPUState *env)
2248{
2249 fprintf(stderr, "setup_frame: not implemented\n");
2250}
2251
pbrook624f7972008-05-31 16:11:38 +00002252static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002253 target_siginfo_t *info,
2254 target_sigset_t *set, CPUState *env)
2255{
2256 fprintf(stderr, "setup_rt_frame: not implemented\n");
2257}
2258
2259long do_sigreturn(CPUState *env)
2260{
2261 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002262 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002263}
2264
2265long do_rt_sigreturn(CPUState *env)
2266{
2267 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002268 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002269}
2270
thsd26bc212007-11-08 18:05:37 +00002271#elif defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002272
2273struct target_sigcontext {
2274 uint32_t sc_regmask; /* Unused */
2275 uint32_t sc_status;
2276 uint64_t sc_pc;
2277 uint64_t sc_regs[32];
2278 uint64_t sc_fpregs[32];
2279 uint32_t sc_ownedfp; /* Unused */
2280 uint32_t sc_fpc_csr;
2281 uint32_t sc_fpc_eir; /* Unused */
2282 uint32_t sc_used_math;
2283 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
2284 uint64_t sc_mdhi;
2285 uint64_t sc_mdlo;
2286 target_ulong sc_hi1; /* Was sc_cause */
2287 target_ulong sc_lo1; /* Was sc_badvaddr */
2288 target_ulong sc_hi2; /* Was sc_sigset[4] */
2289 target_ulong sc_lo2;
2290 target_ulong sc_hi3;
2291 target_ulong sc_lo3;
2292};
2293
2294struct sigframe {
2295 uint32_t sf_ass[4]; /* argument save space for o32 */
2296 uint32_t sf_code[2]; /* signal trampoline */
2297 struct target_sigcontext sf_sc;
2298 target_sigset_t sf_mask;
2299};
2300
2301/* Install trampoline to jump back from signal handler */
2302static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2303{
2304 int err;
2305
2306 /*
2307 * Set up the return code ...
2308 *
2309 * li v0, __NR__foo_sigreturn
2310 * syscall
2311 */
2312
2313 err = __put_user(0x24020000 + syscall, tramp + 0);
2314 err |= __put_user(0x0000000c , tramp + 1);
2315 /* flush_cache_sigtramp((unsigned long) tramp); */
2316 return err;
2317}
2318
2319static inline int
2320setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2321{
2322 int err = 0;
2323
thsb5dc7732008-06-27 10:02:35 +00002324 err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002325
thsb5dc7732008-06-27 10:02:35 +00002326#define save_gp_reg(i) do { \
2327 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002328 } while(0)
2329 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
2330 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
2331 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
2332 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
2333 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
2334 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
2335 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
2336 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
2337 save_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002338#undef save_gp_reg
bellard106ec872006-06-27 21:08:10 +00002339
thsb5dc7732008-06-27 10:02:35 +00002340 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2341 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002342
2343 /* Not used yet, but might be useful if we ever have DSP suppport */
2344#if 0
2345 if (cpu_has_dsp) {
2346 err |= __put_user(mfhi1(), &sc->sc_hi1);
2347 err |= __put_user(mflo1(), &sc->sc_lo1);
2348 err |= __put_user(mfhi2(), &sc->sc_hi2);
2349 err |= __put_user(mflo2(), &sc->sc_lo2);
2350 err |= __put_user(mfhi3(), &sc->sc_hi3);
2351 err |= __put_user(mflo3(), &sc->sc_lo3);
2352 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2353 }
2354 /* same with 64 bit */
ths388bb212007-05-13 13:58:00 +00002355#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002356 err |= __put_user(regs->hi, &sc->sc_hi[0]);
2357 err |= __put_user(regs->lo, &sc->sc_lo[0]);
2358 if (cpu_has_dsp) {
2359 err |= __put_user(mfhi1(), &sc->sc_hi[1]);
2360 err |= __put_user(mflo1(), &sc->sc_lo[1]);
2361 err |= __put_user(mfhi2(), &sc->sc_hi[2]);
2362 err |= __put_user(mflo2(), &sc->sc_lo[2]);
2363 err |= __put_user(mfhi3(), &sc->sc_hi[3]);
2364 err |= __put_user(mflo3(), &sc->sc_lo[3]);
2365 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2366 }
ths388bb212007-05-13 13:58:00 +00002367#endif
2368#endif
bellard106ec872006-06-27 21:08:10 +00002369
ths388bb212007-05-13 13:58:00 +00002370#if 0
bellard106ec872006-06-27 21:08:10 +00002371 err |= __put_user(!!used_math(), &sc->sc_used_math);
2372
2373 if (!used_math())
2374 goto out;
2375
2376 /*
2377 * Save FPU state to signal context. Signal handler will "inherit"
2378 * current FPU state.
2379 */
2380 preempt_disable();
2381
2382 if (!is_fpu_owner()) {
2383 own_fpu();
2384 restore_fp(current);
2385 }
2386 err |= save_fp_context(sc);
2387
2388 preempt_enable();
2389 out:
2390#endif
2391 return err;
2392}
2393
2394static inline int
2395restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2396{
2397 int err = 0;
2398
2399 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2400
thsb5dc7732008-06-27 10:02:35 +00002401 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2402 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002403
thsead93602007-09-06 00:18:15 +00002404#define restore_gp_reg(i) do { \
thsb5dc7732008-06-27 10:02:35 +00002405 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002406 } while(0)
2407 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
2408 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
2409 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
2410 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
2411 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
2412 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
2413 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
2414 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
2415 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
2416 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
2417 restore_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002418#undef restore_gp_reg
bellard106ec872006-06-27 21:08:10 +00002419
2420#if 0
2421 if (cpu_has_dsp) {
2422 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
2423 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
2424 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
2425 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
2426 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
2427 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2428 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2429 }
ths388bb212007-05-13 13:58:00 +00002430#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002431 err |= __get_user(regs->hi, &sc->sc_hi[0]);
2432 err |= __get_user(regs->lo, &sc->sc_lo[0]);
2433 if (cpu_has_dsp) {
2434 err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
2435 err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
2436 err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
2437 err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
2438 err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
2439 err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
2440 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2441 }
ths388bb212007-05-13 13:58:00 +00002442#endif
bellard106ec872006-06-27 21:08:10 +00002443
2444 err |= __get_user(used_math, &sc->sc_used_math);
2445 conditional_used_math(used_math);
2446
2447 preempt_disable();
2448
2449 if (used_math()) {
2450 /* restore fpu context if we have used it before */
2451 own_fpu();
2452 err |= restore_fp_context(sc);
2453 } else {
2454 /* signal handler may have used FPU. Give it up. */
2455 lose_fpu();
2456 }
2457
2458 preempt_enable();
2459#endif
2460 return err;
2461}
2462/*
2463 * Determine which stack to use..
2464 */
bellard579a97f2007-11-11 14:26:47 +00002465static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00002466get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002467{
2468 unsigned long sp;
2469
2470 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002471 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002472
2473 /*
2474 * FPU emulator may have it's own trampoline active just
2475 * above the user stack, 16-bytes before the next lowest
2476 * 16 byte boundary. Try to avoid trashing it.
2477 */
2478 sp -= 32;
2479
bellard106ec872006-06-27 21:08:10 +00002480 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002481 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002482 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2483 }
bellard106ec872006-06-27 21:08:10 +00002484
bellard579a97f2007-11-11 14:26:47 +00002485 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002486}
2487
bellard579a97f2007-11-11 14:26:47 +00002488/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002489static void setup_frame(int sig, struct target_sigaction * ka,
bellard579a97f2007-11-11 14:26:47 +00002490 target_sigset_t *set, CPUState *regs)
bellard106ec872006-06-27 21:08:10 +00002491{
2492 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002493 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002494 int i;
2495
bellard579a97f2007-11-11 14:26:47 +00002496 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2497 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002498 goto give_sigsegv;
2499
2500 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2501
2502 if(setup_sigcontext(regs, &frame->sf_sc))
2503 goto give_sigsegv;
2504
2505 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2506 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2507 goto give_sigsegv;
2508 }
2509
2510 /*
2511 * Arguments to signal handler:
2512 *
2513 * a0 = signal number
2514 * a1 = 0 (should be cause)
2515 * a2 = pointer to struct sigcontext
2516 *
2517 * $25 and PC point to the signal handler, $29 points to the
2518 * struct sigframe.
2519 */
thsb5dc7732008-06-27 10:02:35 +00002520 regs->active_tc.gpr[ 4] = sig;
2521 regs->active_tc.gpr[ 5] = 0;
2522 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2523 regs->active_tc.gpr[29] = frame_addr;
2524 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002525 /* The original kernel code sets CP0_EPC to the handler
2526 * since it returns to userland using eret
2527 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002528 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
bellard579a97f2007-11-11 14:26:47 +00002529 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002530 return;
2531
2532give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002533 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002534 force_sig(TARGET_SIGSEGV/*, current*/);
ths5fafdf22007-09-16 21:08:06 +00002535 return;
bellard106ec872006-06-27 21:08:10 +00002536}
2537
2538long do_sigreturn(CPUState *regs)
2539{
ths388bb212007-05-13 13:58:00 +00002540 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002541 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002542 sigset_t blocked;
2543 target_sigset_t target_set;
2544 int i;
bellard106ec872006-06-27 21:08:10 +00002545
2546#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002547 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002548#endif
thsb5dc7732008-06-27 10:02:35 +00002549 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002550 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002551 goto badframe;
2552
ths388bb212007-05-13 13:58:00 +00002553 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002554 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2555 goto badframe;
ths388bb212007-05-13 13:58:00 +00002556 }
bellard106ec872006-06-27 21:08:10 +00002557
ths388bb212007-05-13 13:58:00 +00002558 target_to_host_sigset_internal(&blocked, &target_set);
2559 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002560
ths388bb212007-05-13 13:58:00 +00002561 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002562 goto badframe;
2563
2564#if 0
ths388bb212007-05-13 13:58:00 +00002565 /*
2566 * Don't let your children do this ...
2567 */
2568 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002569 "move\t$29, %0\n\t"
2570 "j\tsyscall_exit"
2571 :/* no outputs */
2572 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002573 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002574#endif
ths3b46e622007-09-17 08:09:54 +00002575
thsb5dc7732008-06-27 10:02:35 +00002576 regs->active_tc.PC = regs->CP0_EPC;
ths388bb212007-05-13 13:58:00 +00002577 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002578 * maybe a problem with nested signals ? */
2579 regs->CP0_EPC = 0;
2580 return 0;
2581
2582badframe:
ths388bb212007-05-13 13:58:00 +00002583 force_sig(TARGET_SIGSEGV/*, current*/);
2584 return 0;
bellard106ec872006-06-27 21:08:10 +00002585}
2586
pbrook624f7972008-05-31 16:11:38 +00002587static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard106ec872006-06-27 21:08:10 +00002588 target_siginfo_t *info,
2589 target_sigset_t *set, CPUState *env)
2590{
2591 fprintf(stderr, "setup_rt_frame: not implemented\n");
2592}
2593
2594long do_rt_sigreturn(CPUState *env)
2595{
2596 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002597 return -TARGET_ENOSYS;
bellard106ec872006-06-27 21:08:10 +00002598}
bellard6d5e2162004-09-30 22:04:13 +00002599
thsc3b5bc82007-12-02 06:31:25 +00002600#elif defined(TARGET_SH4)
2601
2602/*
2603 * code and data structures from linux kernel:
2604 * include/asm-sh/sigcontext.h
2605 * arch/sh/kernel/signal.c
2606 */
2607
2608struct target_sigcontext {
2609 target_ulong oldmask;
2610
2611 /* CPU registers */
2612 target_ulong sc_gregs[16];
2613 target_ulong sc_pc;
2614 target_ulong sc_pr;
2615 target_ulong sc_sr;
2616 target_ulong sc_gbr;
2617 target_ulong sc_mach;
2618 target_ulong sc_macl;
2619
2620 /* FPU registers */
2621 target_ulong sc_fpregs[16];
2622 target_ulong sc_xfpregs[16];
2623 unsigned int sc_fpscr;
2624 unsigned int sc_fpul;
2625 unsigned int sc_ownedfp;
2626};
2627
2628struct target_sigframe
2629{
2630 struct target_sigcontext sc;
2631 target_ulong extramask[TARGET_NSIG_WORDS-1];
2632 uint16_t retcode[3];
2633};
2634
2635
2636struct target_ucontext {
2637 target_ulong uc_flags;
2638 struct target_ucontext *uc_link;
2639 target_stack_t uc_stack;
2640 struct target_sigcontext uc_mcontext;
2641 target_sigset_t uc_sigmask; /* mask last for extensibility */
2642};
2643
2644struct target_rt_sigframe
2645{
2646 struct target_siginfo info;
2647 struct target_ucontext uc;
2648 uint16_t retcode[3];
2649};
2650
2651
2652#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
2653#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
2654
pbrook624f7972008-05-31 16:11:38 +00002655static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002656 unsigned long sp, size_t frame_size)
2657{
pbrook624f7972008-05-31 16:11:38 +00002658 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00002659 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2660 }
2661
2662 return (sp - frame_size) & -8ul;
2663}
2664
2665static int setup_sigcontext(struct target_sigcontext *sc,
2666 CPUState *regs, unsigned long mask)
2667{
2668 int err = 0;
2669
2670#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
2671 COPY(gregs[0]); COPY(gregs[1]);
2672 COPY(gregs[2]); COPY(gregs[3]);
2673 COPY(gregs[4]); COPY(gregs[5]);
2674 COPY(gregs[6]); COPY(gregs[7]);
2675 COPY(gregs[8]); COPY(gregs[9]);
2676 COPY(gregs[10]); COPY(gregs[11]);
2677 COPY(gregs[12]); COPY(gregs[13]);
2678 COPY(gregs[14]); COPY(gregs[15]);
2679 COPY(gbr); COPY(mach);
2680 COPY(macl); COPY(pr);
2681 COPY(sr); COPY(pc);
2682#undef COPY
2683
2684 /* todo: save FPU registers here */
2685
2686 /* non-iBCS2 extensions.. */
2687 err |= __put_user(mask, &sc->oldmask);
2688
2689 return err;
2690}
2691
2692static int restore_sigcontext(struct CPUState *regs,
2693 struct target_sigcontext *sc)
2694{
2695 unsigned int err = 0;
2696
2697#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
2698 COPY(gregs[1]);
2699 COPY(gregs[2]); COPY(gregs[3]);
2700 COPY(gregs[4]); COPY(gregs[5]);
2701 COPY(gregs[6]); COPY(gregs[7]);
2702 COPY(gregs[8]); COPY(gregs[9]);
2703 COPY(gregs[10]); COPY(gregs[11]);
2704 COPY(gregs[12]); COPY(gregs[13]);
2705 COPY(gregs[14]); COPY(gregs[15]);
2706 COPY(gbr); COPY(mach);
2707 COPY(macl); COPY(pr);
2708 COPY(sr); COPY(pc);
2709#undef COPY
2710
2711 /* todo: restore FPU registers here */
2712
2713 regs->tra = -1; /* disable syscall checks */
2714 return err;
2715}
2716
pbrook624f7972008-05-31 16:11:38 +00002717static void setup_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002718 target_sigset_t *set, CPUState *regs)
2719{
2720 struct target_sigframe *frame;
2721 abi_ulong frame_addr;
2722 int i;
2723 int err = 0;
2724 int signal;
2725
2726 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2727 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2728 goto give_sigsegv;
2729
2730 signal = current_exec_domain_sig(sig);
2731
2732 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
2733
2734 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2735 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
2736 }
2737
2738 /* Set up to return from userspace. If provided, use a stub
2739 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002740 if (ka->sa_flags & TARGET_SA_RESTORER) {
2741 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002742 } else {
2743 /* Generate return code (system call to sigreturn) */
2744 err |= __put_user(MOVW(2), &frame->retcode[0]);
2745 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2746 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
2747 regs->pr = (unsigned long) frame->retcode;
2748 }
2749
2750 if (err)
2751 goto give_sigsegv;
2752
2753 /* Set up registers for signal handler */
2754 regs->gregs[15] = (unsigned long) frame;
2755 regs->gregs[4] = signal; /* Arg for signal handler */
2756 regs->gregs[5] = 0;
2757 regs->gregs[6] = (unsigned long) &frame->sc;
pbrook624f7972008-05-31 16:11:38 +00002758 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002759
2760 unlock_user_struct(frame, frame_addr, 1);
2761 return;
2762
2763give_sigsegv:
2764 unlock_user_struct(frame, frame_addr, 1);
2765 force_sig(SIGSEGV);
2766}
2767
pbrook624f7972008-05-31 16:11:38 +00002768static void setup_rt_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002769 target_siginfo_t *info,
2770 target_sigset_t *set, CPUState *regs)
2771{
2772 struct target_rt_sigframe *frame;
2773 abi_ulong frame_addr;
2774 int i;
2775 int err = 0;
2776 int signal;
2777
2778 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2779 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2780 goto give_sigsegv;
2781
2782 signal = current_exec_domain_sig(sig);
2783
2784 err |= copy_siginfo_to_user(&frame->info, info);
2785
2786 /* Create the ucontext. */
2787 err |= __put_user(0, &frame->uc.uc_flags);
2788 err |= __put_user(0, (unsigned long *)&frame->uc.uc_link);
balrog526ccb72008-07-16 12:13:52 +00002789 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
thsc3b5bc82007-12-02 06:31:25 +00002790 &frame->uc.uc_stack.ss_sp);
2791 err |= __put_user(sas_ss_flags(regs->gregs[15]),
2792 &frame->uc.uc_stack.ss_flags);
2793 err |= __put_user(target_sigaltstack_used.ss_size,
2794 &frame->uc.uc_stack.ss_size);
2795 err |= setup_sigcontext(&frame->uc.uc_mcontext,
2796 regs, set->sig[0]);
2797 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2798 err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]);
2799 }
2800
2801 /* Set up to return from userspace. If provided, use a stub
2802 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002803 if (ka->sa_flags & TARGET_SA_RESTORER) {
2804 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002805 } else {
2806 /* Generate return code (system call to sigreturn) */
2807 err |= __put_user(MOVW(2), &frame->retcode[0]);
2808 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2809 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
2810 regs->pr = (unsigned long) frame->retcode;
2811 }
2812
2813 if (err)
2814 goto give_sigsegv;
2815
2816 /* Set up registers for signal handler */
2817 regs->gregs[15] = (unsigned long) frame;
2818 regs->gregs[4] = signal; /* Arg for signal handler */
2819 regs->gregs[5] = (unsigned long) &frame->info;
2820 regs->gregs[6] = (unsigned long) &frame->uc;
pbrook624f7972008-05-31 16:11:38 +00002821 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002822
2823 unlock_user_struct(frame, frame_addr, 1);
2824 return;
2825
2826give_sigsegv:
2827 unlock_user_struct(frame, frame_addr, 1);
2828 force_sig(SIGSEGV);
2829}
2830
2831long do_sigreturn(CPUState *regs)
2832{
2833 struct target_sigframe *frame;
2834 abi_ulong frame_addr;
2835 sigset_t blocked;
2836 target_sigset_t target_set;
2837 int i;
2838 int err = 0;
2839
2840#if defined(DEBUG_SIGNAL)
2841 fprintf(stderr, "do_sigreturn\n");
2842#endif
2843 frame_addr = regs->gregs[15];
2844 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2845 goto badframe;
2846
2847 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
2848 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2849 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
2850 }
2851
2852 if (err)
2853 goto badframe;
2854
2855 target_to_host_sigset_internal(&blocked, &target_set);
2856 sigprocmask(SIG_SETMASK, &blocked, NULL);
2857
2858 if (restore_sigcontext(regs, &frame->sc))
2859 goto badframe;
2860
2861 unlock_user_struct(frame, frame_addr, 0);
2862 return regs->gregs[0];
2863
2864badframe:
2865 unlock_user_struct(frame, frame_addr, 0);
2866 force_sig(TARGET_SIGSEGV);
2867 return 0;
2868}
2869
2870long do_rt_sigreturn(CPUState *regs)
2871{
2872 struct target_rt_sigframe *frame;
2873 abi_ulong frame_addr;
2874 sigset_t blocked;
2875
2876#if defined(DEBUG_SIGNAL)
2877 fprintf(stderr, "do_rt_sigreturn\n");
2878#endif
2879 frame_addr = regs->gregs[15];
2880 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2881 goto badframe;
2882
2883 target_to_host_sigset(&blocked, &frame->uc.uc_sigmask);
2884 sigprocmask(SIG_SETMASK, &blocked, NULL);
2885
2886 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
2887 goto badframe;
2888
2889 if (do_sigaltstack(frame_addr +
2890 offsetof(struct target_rt_sigframe, uc.uc_stack),
2891 0, get_sp_from_cpustate(regs)) == -EFAULT)
2892 goto badframe;
2893
2894 unlock_user_struct(frame, frame_addr, 0);
2895 return regs->gregs[0];
2896
2897badframe:
2898 unlock_user_struct(frame, frame_addr, 0);
2899 force_sig(TARGET_SIGSEGV);
2900 return 0;
2901}
edgar_iglb6d3abd2008-02-28 11:29:27 +00002902#elif defined(TARGET_CRIS)
2903
2904struct target_sigcontext {
2905 struct target_pt_regs regs; /* needs to be first */
2906 uint32_t oldmask;
2907 uint32_t usp; /* usp before stacking this gunk on it */
2908};
2909
2910/* Signal frames. */
2911struct target_signal_frame {
2912 struct target_sigcontext sc;
2913 uint32_t extramask[TARGET_NSIG_WORDS - 1];
2914 uint8_t retcode[8]; /* Trampoline code. */
2915};
2916
2917struct rt_signal_frame {
2918 struct siginfo *pinfo;
2919 void *puc;
2920 struct siginfo info;
2921 struct ucontext uc;
2922 uint8_t retcode[8]; /* Trampoline code. */
2923};
2924
2925static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
2926{
edgar_igl9664d922008-03-03 22:23:53 +00002927 __put_user(env->regs[0], &sc->regs.r0);
2928 __put_user(env->regs[1], &sc->regs.r1);
2929 __put_user(env->regs[2], &sc->regs.r2);
2930 __put_user(env->regs[3], &sc->regs.r3);
2931 __put_user(env->regs[4], &sc->regs.r4);
2932 __put_user(env->regs[5], &sc->regs.r5);
2933 __put_user(env->regs[6], &sc->regs.r6);
2934 __put_user(env->regs[7], &sc->regs.r7);
2935 __put_user(env->regs[8], &sc->regs.r8);
2936 __put_user(env->regs[9], &sc->regs.r9);
2937 __put_user(env->regs[10], &sc->regs.r10);
2938 __put_user(env->regs[11], &sc->regs.r11);
2939 __put_user(env->regs[12], &sc->regs.r12);
2940 __put_user(env->regs[13], &sc->regs.r13);
2941 __put_user(env->regs[14], &sc->usp);
2942 __put_user(env->regs[15], &sc->regs.acr);
2943 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
2944 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
2945 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002946}
edgar_igl9664d922008-03-03 22:23:53 +00002947
edgar_iglb6d3abd2008-02-28 11:29:27 +00002948static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
2949{
edgar_igl9664d922008-03-03 22:23:53 +00002950 __get_user(env->regs[0], &sc->regs.r0);
2951 __get_user(env->regs[1], &sc->regs.r1);
2952 __get_user(env->regs[2], &sc->regs.r2);
2953 __get_user(env->regs[3], &sc->regs.r3);
2954 __get_user(env->regs[4], &sc->regs.r4);
2955 __get_user(env->regs[5], &sc->regs.r5);
2956 __get_user(env->regs[6], &sc->regs.r6);
2957 __get_user(env->regs[7], &sc->regs.r7);
2958 __get_user(env->regs[8], &sc->regs.r8);
2959 __get_user(env->regs[9], &sc->regs.r9);
2960 __get_user(env->regs[10], &sc->regs.r10);
2961 __get_user(env->regs[11], &sc->regs.r11);
2962 __get_user(env->regs[12], &sc->regs.r12);
2963 __get_user(env->regs[13], &sc->regs.r13);
2964 __get_user(env->regs[14], &sc->usp);
2965 __get_user(env->regs[15], &sc->regs.acr);
2966 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
2967 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
2968 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002969}
2970
edgar_igl9664d922008-03-03 22:23:53 +00002971static abi_ulong get_sigframe(CPUState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00002972{
edgar_igl9664d922008-03-03 22:23:53 +00002973 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002974 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00002975 sp = (env->regs[R_SP] & ~3);
2976 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002977}
2978
pbrook624f7972008-05-31 16:11:38 +00002979static void setup_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00002980 target_sigset_t *set, CPUState *env)
2981{
2982 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00002983 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002984 int err = 0;
2985 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002986
edgar_igl9664d922008-03-03 22:23:53 +00002987 frame_addr = get_sigframe(env, sizeof *frame);
2988 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00002989 goto badframe;
2990
2991 /*
2992 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
2993 * use this trampoline anymore but it sets it up for GDB.
2994 * In QEMU, using the trampoline simplifies things a bit so we use it.
2995 *
2996 * This is movu.w __NR_sigreturn, r9; break 13;
2997 */
2998 err |= __put_user(0x9c5f, frame->retcode+0);
2999 err |= __put_user(TARGET_NR_sigreturn,
3000 frame->retcode+2);
3001 err |= __put_user(0xe93d, frame->retcode+4);
3002
3003 /* Save the mask. */
3004 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3005 if (err)
3006 goto badframe;
3007
3008 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3009 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3010 goto badframe;
3011 }
3012
3013 setup_sigcontext(&frame->sc, env);
3014
3015 /* Move the stack and setup the arguments for the handler. */
balrog526ccb72008-07-16 12:13:52 +00003016 env->regs[R_SP] = (uint32_t) (unsigned long) frame;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003017 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003018 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003019 /* Link SRP so the guest returns through the trampoline. */
balrog526ccb72008-07-16 12:13:52 +00003020 env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003021
edgar_igl9664d922008-03-03 22:23:53 +00003022 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003023 return;
3024 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003025 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003026 force_sig(TARGET_SIGSEGV);
3027}
3028
pbrook624f7972008-05-31 16:11:38 +00003029static void setup_rt_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00003030 target_siginfo_t *info,
3031 target_sigset_t *set, CPUState *env)
3032{
3033 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3034}
3035
3036long do_sigreturn(CPUState *env)
3037{
3038 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003039 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003040 target_sigset_t target_set;
3041 sigset_t set;
3042 int i;
3043
edgar_igl9664d922008-03-03 22:23:53 +00003044 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003045 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003046 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003047 goto badframe;
3048
3049 /* Restore blocked signals */
3050 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3051 goto badframe;
3052 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3053 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3054 goto badframe;
3055 }
3056 target_to_host_sigset_internal(&set, &target_set);
3057 sigprocmask(SIG_SETMASK, &set, NULL);
3058
3059 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003060 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003061 return env->regs[10];
3062 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003063 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003064 force_sig(TARGET_SIGSEGV);
3065}
3066
3067long do_rt_sigreturn(CPUState *env)
3068{
3069 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3070 return -TARGET_ENOSYS;
3071}
thsc3b5bc82007-12-02 06:31:25 +00003072
bellardb346ff42003-06-15 20:05:50 +00003073#else
3074
pbrook624f7972008-05-31 16:11:38 +00003075static void setup_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003076 target_sigset_t *set, CPUState *env)
3077{
3078 fprintf(stderr, "setup_frame: not implemented\n");
3079}
3080
pbrook624f7972008-05-31 16:11:38 +00003081static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003082 target_siginfo_t *info,
3083 target_sigset_t *set, CPUState *env)
3084{
3085 fprintf(stderr, "setup_rt_frame: not implemented\n");
3086}
3087
3088long do_sigreturn(CPUState *env)
3089{
3090 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003091 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003092}
3093
3094long do_rt_sigreturn(CPUState *env)
3095{
3096 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003097 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003098}
3099
bellard66fb9762003-03-23 01:06:05 +00003100#endif
3101
pbrook624f7972008-05-31 16:11:38 +00003102void process_pending_signals(CPUState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00003103{
3104 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00003105 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00003106 sigset_t set, old_set;
3107 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00003108 struct emulated_sigtable *k;
3109 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00003110 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00003111 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00003112
pbrook624f7972008-05-31 16:11:38 +00003113 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00003114 return;
3115
pbrook624f7972008-05-31 16:11:38 +00003116 /* FIXME: This is not threadsafe. */
3117 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00003118 for(sig = 1; sig <= TARGET_NSIG; sig++) {
3119 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00003120 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00003121 k++;
bellard31e31b82003-02-18 22:55:36 +00003122 }
3123 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00003124 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00003125 return;
bellard66fb9762003-03-23 01:06:05 +00003126
bellard31e31b82003-02-18 22:55:36 +00003127 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00003128#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00003129 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00003130#endif
3131 /* dequeue signal */
3132 q = k->first;
3133 k->first = q->next;
3134 if (!k->first)
3135 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00003136
bellard1fddef42005-04-17 19:16:13 +00003137 sig = gdb_handlesig (cpu_env, sig);
3138 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00003139 sa = NULL;
3140 handler = TARGET_SIG_IGN;
3141 } else {
3142 sa = &sigact_table[sig - 1];
3143 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00003144 }
bellard66fb9762003-03-23 01:06:05 +00003145
bellard66fb9762003-03-23 01:06:05 +00003146 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00003147 /* default handler : ignore some signal. The other are job control or fatal */
3148 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
3149 kill(getpid(),SIGSTOP);
3150 } else if (sig != TARGET_SIGCHLD &&
3151 sig != TARGET_SIGURG &&
3152 sig != TARGET_SIGWINCH &&
3153 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00003154 force_sig(sig);
3155 }
3156 } else if (handler == TARGET_SIG_IGN) {
3157 /* ignore sig */
3158 } else if (handler == TARGET_SIG_ERR) {
3159 force_sig(sig);
3160 } else {
bellard9de5e442003-03-23 16:49:39 +00003161 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00003162 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00003163 /* SA_NODEFER indicates that the current signal should not be
3164 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00003165 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00003166 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00003167
bellard9de5e442003-03-23 16:49:39 +00003168 /* block signals in the handler using Linux */
3169 sigprocmask(SIG_BLOCK, &set, &old_set);
3170 /* save the previous blocked signal state to restore it at the
3171 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00003172 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00003173
bellardbc8a22c2003-03-30 21:02:40 +00003174 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00003175#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00003176 {
3177 CPUX86State *env = cpu_env;
3178 if (env->eflags & VM_MASK)
3179 save_v86_state(env);
3180 }
3181#endif
bellard9de5e442003-03-23 16:49:39 +00003182 /* prepare the stack frame of the virtual CPU */
pbrook624f7972008-05-31 16:11:38 +00003183 if (sa->sa_flags & TARGET_SA_SIGINFO)
3184 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00003185 else
pbrook624f7972008-05-31 16:11:38 +00003186 setup_frame(sig, sa, &target_old_set, cpu_env);
3187 if (sa->sa_flags & TARGET_SA_RESETHAND)
3188 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00003189 }
bellard66fb9762003-03-23 01:06:05 +00003190 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00003191 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00003192}