blob: fc37dc11ffd58494ad9bc1291998b33e1dea3ab4 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
blueswir1530e7612009-01-05 18:11:53 +000018 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 * MA 02110-1301, USA.
bellard31e31b82003-02-18 22:55:36 +000020 */
21#include <stdlib.h>
22#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000023#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000025#include <unistd.h>
bellard31e31b82003-02-18 22:55:36 +000026#include <signal.h>
bellard66fb9762003-03-23 01:06:05 +000027#include <errno.h>
bellard31e31b82003-02-18 22:55:36 +000028#include <sys/ucontext.h>
29
bellard3ef693a2003-03-23 20:17:16 +000030#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000031#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000032#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000033
34//#define DEBUG_SIGNAL
35
blueswir1249c4c32008-10-05 11:09:37 +000036static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000037 .ss_sp = 0,
38 .ss_size = 0,
39 .ss_flags = TARGET_SS_DISABLE,
40};
41
pbrook624f7972008-05-31 16:11:38 +000042static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000043
ths5fafdf22007-09-16 21:08:06 +000044static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000045 void *puc);
46
bellard9e5f5282003-07-13 17:33:54 +000047static uint8_t host_to_target_signal_table[65] = {
48 [SIGHUP] = TARGET_SIGHUP,
49 [SIGINT] = TARGET_SIGINT,
50 [SIGQUIT] = TARGET_SIGQUIT,
51 [SIGILL] = TARGET_SIGILL,
52 [SIGTRAP] = TARGET_SIGTRAP,
53 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000054/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000055 [SIGBUS] = TARGET_SIGBUS,
56 [SIGFPE] = TARGET_SIGFPE,
57 [SIGKILL] = TARGET_SIGKILL,
58 [SIGUSR1] = TARGET_SIGUSR1,
59 [SIGSEGV] = TARGET_SIGSEGV,
60 [SIGUSR2] = TARGET_SIGUSR2,
61 [SIGPIPE] = TARGET_SIGPIPE,
62 [SIGALRM] = TARGET_SIGALRM,
63 [SIGTERM] = TARGET_SIGTERM,
64#ifdef SIGSTKFLT
65 [SIGSTKFLT] = TARGET_SIGSTKFLT,
66#endif
67 [SIGCHLD] = TARGET_SIGCHLD,
68 [SIGCONT] = TARGET_SIGCONT,
69 [SIGSTOP] = TARGET_SIGSTOP,
70 [SIGTSTP] = TARGET_SIGTSTP,
71 [SIGTTIN] = TARGET_SIGTTIN,
72 [SIGTTOU] = TARGET_SIGTTOU,
73 [SIGURG] = TARGET_SIGURG,
74 [SIGXCPU] = TARGET_SIGXCPU,
75 [SIGXFSZ] = TARGET_SIGXFSZ,
76 [SIGVTALRM] = TARGET_SIGVTALRM,
77 [SIGPROF] = TARGET_SIGPROF,
78 [SIGWINCH] = TARGET_SIGWINCH,
79 [SIGIO] = TARGET_SIGIO,
80 [SIGPWR] = TARGET_SIGPWR,
81 [SIGSYS] = TARGET_SIGSYS,
82 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000083 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
84 host libpthread signals. This assumes noone actually uses SIGRTMAX :-/
85 To fix this properly we need to do manual signal delivery multiplexed
86 over a single host signal. */
87 [__SIGRTMIN] = __SIGRTMAX,
88 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000089};
90static uint8_t target_to_host_signal_table[65];
91
thsa04e1342007-09-27 13:57:58 +000092static inline int on_sig_stack(unsigned long sp)
93{
94 return (sp - target_sigaltstack_used.ss_sp
95 < target_sigaltstack_used.ss_size);
96}
97
98static inline int sas_ss_flags(unsigned long sp)
99{
100 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
101 : on_sig_stack(sp) ? SS_ONSTACK : 0);
102}
103
bellard31e31b82003-02-18 22:55:36 +0000104static inline int host_to_target_signal(int sig)
105{
pbrook4cb05962008-05-30 18:05:19 +0000106 if (sig > 64)
107 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000108 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000109}
110
pbrook4cb05962008-05-30 18:05:19 +0000111int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000112{
pbrook4cb05962008-05-30 18:05:19 +0000113 if (sig > 64)
114 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000115 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000116}
117
pbrookf5545b52008-05-30 22:37:07 +0000118static inline void target_sigemptyset(target_sigset_t *set)
119{
120 memset(set, 0, sizeof(*set));
121}
122
123static inline void target_sigaddset(target_sigset_t *set, int signum)
124{
125 signum--;
126 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
127 set->sig[signum / TARGET_NSIG_BPW] |= mask;
128}
129
130static inline int target_sigismember(const target_sigset_t *set, int signum)
131{
132 signum--;
133 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
134 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
135}
136
ths5fafdf22007-09-16 21:08:06 +0000137static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000138 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000139{
140 int i;
pbrookf5545b52008-05-30 22:37:07 +0000141 target_sigemptyset(d);
142 for (i = 1; i <= TARGET_NSIG; i++) {
143 if (sigismember(s, i)) {
144 target_sigaddset(d, host_to_target_signal(i));
145 }
bellard9e5f5282003-07-13 17:33:54 +0000146 }
bellard66fb9762003-03-23 01:06:05 +0000147}
148
bellard92319442004-06-19 16:58:13 +0000149void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
150{
151 target_sigset_t d1;
152 int i;
153
154 host_to_target_sigset_internal(&d1, s);
155 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000156 d->sig[i] = tswapl(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000157}
158
blueswir18fcd3692008-08-17 20:26:25 +0000159static void target_to_host_sigset_internal(sigset_t *d,
160 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000161{
162 int i;
pbrookf5545b52008-05-30 22:37:07 +0000163 sigemptyset(d);
164 for (i = 1; i <= TARGET_NSIG; i++) {
165 if (target_sigismember(s, i)) {
166 sigaddset(d, target_to_host_signal(i));
167 }
168 }
bellard66fb9762003-03-23 01:06:05 +0000169}
170
bellard92319442004-06-19 16:58:13 +0000171void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
172{
173 target_sigset_t s1;
174 int i;
175
176 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000177 s1.sig[i] = tswapl(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000178 target_to_host_sigset_internal(d, &s1);
179}
ths3b46e622007-09-17 08:09:54 +0000180
blueswir1992f48a2007-10-14 16:27:31 +0000181void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000182 const sigset_t *sigset)
183{
bellard9e5f5282003-07-13 17:33:54 +0000184 target_sigset_t d;
185 host_to_target_sigset(&d, sigset);
186 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000187}
188
ths5fafdf22007-09-16 21:08:06 +0000189void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000190 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000191{
bellard9e5f5282003-07-13 17:33:54 +0000192 target_sigset_t d;
193 int i;
194
195 d.sig[0] = *old_sigset;
196 for(i = 1;i < TARGET_NSIG_WORDS; i++)
197 d.sig[i] = 0;
198 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000199}
200
bellard9de5e442003-03-23 16:49:39 +0000201/* siginfo conversion */
202
ths5fafdf22007-09-16 21:08:06 +0000203static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000204 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000205{
bellard9de5e442003-03-23 16:49:39 +0000206 int sig;
207 sig = host_to_target_signal(info->si_signo);
208 tinfo->si_signo = sig;
209 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000210 tinfo->si_code = info->si_code;
ths5fafdf22007-09-16 21:08:06 +0000211 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000212 sig == SIGBUS || sig == SIGTRAP) {
bellard9de5e442003-03-23 16:49:39 +0000213 /* should never come here, but who knows. The information for
214 the target is irrelevant */
215 tinfo->_sifields._sigfault._addr = 0;
ths7f7f7c82007-07-12 11:02:46 +0000216 } else if (sig == SIGIO) {
217 tinfo->_sifields._sigpoll._fd = info->si_fd;
bellard9de5e442003-03-23 16:49:39 +0000218 } else if (sig >= TARGET_SIGRTMIN) {
219 tinfo->_sifields._rt._pid = info->si_pid;
220 tinfo->_sifields._rt._uid = info->si_uid;
221 /* XXX: potential problem if 64 bit */
ths5fafdf22007-09-16 21:08:06 +0000222 tinfo->_sifields._rt._sigval.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000223 (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000224 }
bellard66fb9762003-03-23 01:06:05 +0000225}
226
ths5fafdf22007-09-16 21:08:06 +0000227static void tswap_siginfo(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000228 const target_siginfo_t *info)
229{
230 int sig;
231 sig = info->si_signo;
232 tinfo->si_signo = tswap32(sig);
233 tinfo->si_errno = tswap32(info->si_errno);
234 tinfo->si_code = tswap32(info->si_code);
ths5fafdf22007-09-16 21:08:06 +0000235 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000236 sig == SIGBUS || sig == SIGTRAP) {
ths5fafdf22007-09-16 21:08:06 +0000237 tinfo->_sifields._sigfault._addr =
bellard9de5e442003-03-23 16:49:39 +0000238 tswapl(info->_sifields._sigfault._addr);
ths7f7f7c82007-07-12 11:02:46 +0000239 } else if (sig == SIGIO) {
240 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
bellard9de5e442003-03-23 16:49:39 +0000241 } else if (sig >= TARGET_SIGRTMIN) {
242 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
243 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000244 tinfo->_sifields._rt._sigval.sival_ptr =
bellard9de5e442003-03-23 16:49:39 +0000245 tswapl(info->_sifields._rt._sigval.sival_ptr);
246 }
247}
248
249
250void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
251{
252 host_to_target_siginfo_noswap(tinfo, info);
253 tswap_siginfo(tinfo, tinfo);
254}
255
256/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000257/* XXX: find a solution for 64 bit (additional malloced data is needed) */
bellard9de5e442003-03-23 16:49:39 +0000258void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000259{
260 info->si_signo = tswap32(tinfo->si_signo);
261 info->si_errno = tswap32(tinfo->si_errno);
262 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000263 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
264 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000265 info->si_value.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000266 (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000267}
268
aurel32ca587a82008-12-18 22:44:13 +0000269static int fatal_signal (int sig)
270{
271 switch (sig) {
272 case TARGET_SIGCHLD:
273 case TARGET_SIGURG:
274 case TARGET_SIGWINCH:
275 /* Ignored by default. */
276 return 0;
277 case TARGET_SIGCONT:
278 case TARGET_SIGSTOP:
279 case TARGET_SIGTSTP:
280 case TARGET_SIGTTIN:
281 case TARGET_SIGTTOU:
282 /* Job control signals. */
283 return 0;
284 default:
285 return 1;
286 }
287}
288
bellard31e31b82003-02-18 22:55:36 +0000289void signal_init(void)
290{
291 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000292 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000293 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000294 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000295
bellard9e5f5282003-07-13 17:33:54 +0000296 /* generate signal conversion tables */
297 for(i = 1; i <= 64; i++) {
298 if (host_to_target_signal_table[i] == 0)
299 host_to_target_signal_table[i] = i;
300 }
301 for(i = 1; i <= 64; i++) {
302 j = host_to_target_signal_table[i];
303 target_to_host_signal_table[j] = i;
304 }
ths3b46e622007-09-17 08:09:54 +0000305
bellard9de5e442003-03-23 16:49:39 +0000306 /* set all host signal handlers. ALL signals are blocked during
307 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000308 memset(sigact_table, 0, sizeof(sigact_table));
309
bellard9de5e442003-03-23 16:49:39 +0000310 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000311 act.sa_flags = SA_SIGINFO;
312 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000313 for(i = 1; i <= TARGET_NSIG; i++) {
314 host_sig = target_to_host_signal(i);
315 sigaction(host_sig, NULL, &oact);
316 if (oact.sa_sigaction == (void *)SIG_IGN) {
317 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
318 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
319 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
320 }
321 /* If there's already a handler installed then something has
322 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000323 /* Install some handlers for our own use. We need at least
324 SIGSEGV and SIGBUS, to detect exceptions. We can not just
325 trap all signals because it affects syscall interrupt
326 behavior. But do trap all default-fatal signals. */
327 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000328 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000329 }
bellard31e31b82003-02-18 22:55:36 +0000330}
331
bellard66fb9762003-03-23 01:06:05 +0000332/* signal queue handling */
333
pbrook624f7972008-05-31 16:11:38 +0000334static inline struct sigqueue *alloc_sigqueue(CPUState *env)
bellard66fb9762003-03-23 01:06:05 +0000335{
pbrook624f7972008-05-31 16:11:38 +0000336 TaskState *ts = env->opaque;
337 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000338 if (!q)
339 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000340 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000341 return q;
342}
343
pbrook624f7972008-05-31 16:11:38 +0000344static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000345{
pbrook624f7972008-05-31 16:11:38 +0000346 TaskState *ts = env->opaque;
347 q->next = ts->first_free;
348 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000349}
350
bellard9de5e442003-03-23 16:49:39 +0000351/* abort execution with signal */
malca5e50b22009-02-01 22:19:27 +0000352static void QEMU_NORETURN force_sig(int sig)
bellard66fb9762003-03-23 01:06:05 +0000353{
354 int host_sig;
bellard66fb9762003-03-23 01:06:05 +0000355 host_sig = target_to_host_signal(sig);
ths5fafdf22007-09-16 21:08:06 +0000356 fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
bellard66fb9762003-03-23 01:06:05 +0000357 sig, strsignal(host_sig));
bellard9de5e442003-03-23 16:49:39 +0000358#if 1
aurel32ca587a82008-12-18 22:44:13 +0000359 gdb_signalled(thread_env, sig);
bellard66fb9762003-03-23 01:06:05 +0000360 _exit(-host_sig);
bellard9de5e442003-03-23 16:49:39 +0000361#else
362 {
363 struct sigaction act;
364 sigemptyset(&act.sa_mask);
365 act.sa_flags = SA_SIGINFO;
366 act.sa_sigaction = SIG_DFL;
367 sigaction(SIGABRT, &act, NULL);
368 abort();
369 }
370#endif
bellard66fb9762003-03-23 01:06:05 +0000371}
372
bellard9de5e442003-03-23 16:49:39 +0000373/* queue a signal so that it will be send to the virtual CPU as soon
374 as possible */
pbrook624f7972008-05-31 16:11:38 +0000375int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000376{
pbrook624f7972008-05-31 16:11:38 +0000377 TaskState *ts = env->opaque;
378 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000379 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000380 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000381 int queue;
bellard66fb9762003-03-23 01:06:05 +0000382
bellard9de5e442003-03-23 16:49:39 +0000383#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000384 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000385 sig);
bellard66fb9762003-03-23 01:06:05 +0000386#endif
pbrook624f7972008-05-31 16:11:38 +0000387 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000388 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000389 handler = sigact_table[sig - 1]._sa_handler;
aurel32ca587a82008-12-18 22:44:13 +0000390 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000391 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
392 kill(getpid(),SIGSTOP);
393 return 0;
394 } else
bellard66fb9762003-03-23 01:06:05 +0000395 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000396 if (sig != TARGET_SIGCHLD &&
397 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000398 sig != TARGET_SIGWINCH &&
399 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000400 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000401 } else {
402 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000403 }
aurel32ca587a82008-12-18 22:44:13 +0000404 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000405 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000406 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000407 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000408 force_sig(sig);
409 } else {
bellard9de5e442003-03-23 16:49:39 +0000410 pq = &k->first;
411 if (sig < TARGET_SIGRTMIN) {
412 /* if non real time signal, we queue exactly one signal */
413 if (!k->pending)
414 q = &k->info;
415 else
416 return 0;
417 } else {
418 if (!k->pending) {
419 /* first signal */
420 q = &k->info;
421 } else {
pbrook624f7972008-05-31 16:11:38 +0000422 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000423 if (!q)
424 return -EAGAIN;
425 while (*pq != NULL)
426 pq = &(*pq)->next;
427 }
428 }
429 *pq = q;
430 q->info = *info;
431 q->next = NULL;
432 k->pending = 1;
433 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000434 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000435 return 1; /* indicates that the signal was queued */
436 }
437}
438
ths5fafdf22007-09-16 21:08:06 +0000439static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000440 void *puc)
441{
442 int sig;
443 target_siginfo_t tinfo;
444
445 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000446 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000447 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000448 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000449 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000450 return;
451 }
452
453 /* get target signal number */
454 sig = host_to_target_signal(host_signum);
455 if (sig < 1 || sig > TARGET_NSIG)
456 return;
457#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000458 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000459#endif
460 host_to_target_siginfo_noswap(&tinfo, info);
pbrookd5975362008-06-07 20:50:51 +0000461 if (queue_signal(thread_env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000462 /* interrupt the virtual CPU as soon as possible */
aurel323098dba2009-03-07 21:28:24 +0000463 cpu_exit(thread_env);
bellard66fb9762003-03-23 01:06:05 +0000464 }
bellard31e31b82003-02-18 22:55:36 +0000465}
466
ths0da46a62007-10-20 20:23:07 +0000467/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000468/* compare linux/kernel/signal.c:do_sigaltstack() */
469abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000470{
471 int ret;
472 struct target_sigaltstack oss;
473
474 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000475 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000476 {
477 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
478 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
479 __put_user(sas_ss_flags(sp), &oss.ss_flags);
480 }
481
bellard579a97f2007-11-11 14:26:47 +0000482 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000483 {
bellard579a97f2007-11-11 14:26:47 +0000484 struct target_sigaltstack *uss;
485 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000486
ths0da46a62007-10-20 20:23:07 +0000487 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000488 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000489 || __get_user(ss.ss_sp, &uss->ss_sp)
490 || __get_user(ss.ss_size, &uss->ss_size)
491 || __get_user(ss.ss_flags, &uss->ss_flags))
492 goto out;
bellard579a97f2007-11-11 14:26:47 +0000493 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000494
ths0da46a62007-10-20 20:23:07 +0000495 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000496 if (on_sig_stack(sp))
497 goto out;
498
ths0da46a62007-10-20 20:23:07 +0000499 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000500 if (ss.ss_flags != TARGET_SS_DISABLE
501 && ss.ss_flags != TARGET_SS_ONSTACK
502 && ss.ss_flags != 0)
503 goto out;
504
505 if (ss.ss_flags == TARGET_SS_DISABLE) {
506 ss.ss_size = 0;
507 ss.ss_sp = 0;
508 } else {
ths0da46a62007-10-20 20:23:07 +0000509 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000510 if (ss.ss_size < MINSIGSTKSZ)
511 goto out;
512 }
513
514 target_sigaltstack_used.ss_sp = ss.ss_sp;
515 target_sigaltstack_used.ss_size = ss.ss_size;
516 }
517
bellard579a97f2007-11-11 14:26:47 +0000518 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000519 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000520 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000521 goto out;
thsa04e1342007-09-27 13:57:58 +0000522 }
523
524 ret = 0;
525out:
526 return ret;
527}
528
ths0da46a62007-10-20 20:23:07 +0000529/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000530int do_sigaction(int sig, const struct target_sigaction *act,
531 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000532{
pbrook624f7972008-05-31 16:11:38 +0000533 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000534 struct sigaction act1;
535 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000536 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000537
ths2a913eb2008-11-27 15:46:25 +0000538 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000539 return -EINVAL;
540 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000541#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000542 fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
bellard66fb9762003-03-23 01:06:05 +0000543 sig, (int)act, (int)oact);
544#endif
545 if (oact) {
pbrook624f7972008-05-31 16:11:38 +0000546 oact->_sa_handler = tswapl(k->_sa_handler);
547 oact->sa_flags = tswapl(k->sa_flags);
ths388bb212007-05-13 13:58:00 +0000548#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000549 oact->sa_restorer = tswapl(k->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000550#endif
pbrook624f7972008-05-31 16:11:38 +0000551 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000552 }
553 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000554 /* FIXME: This is not threadsafe. */
555 k->_sa_handler = tswapl(act->_sa_handler);
556 k->sa_flags = tswapl(act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000557#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000558 k->sa_restorer = tswapl(act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000559#endif
pbrook624f7972008-05-31 16:11:38 +0000560 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000561
562 /* we update the host linux signal state */
563 host_sig = target_to_host_signal(sig);
564 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
565 sigfillset(&act1.sa_mask);
566 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000567 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000568 act1.sa_flags |= SA_RESTART;
569 /* NOTE: it is important to update the host kernel signal
570 ignore state to avoid getting unexpected interrupted
571 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000572 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000573 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000574 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000575 if (fatal_signal (sig))
576 act1.sa_sigaction = host_signal_handler;
577 else
578 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000579 } else {
580 act1.sa_sigaction = host_signal_handler;
581 }
ths0da46a62007-10-20 20:23:07 +0000582 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000583 }
bellard66fb9762003-03-23 01:06:05 +0000584 }
ths0da46a62007-10-20 20:23:07 +0000585 return ret;
bellard66fb9762003-03-23 01:06:05 +0000586}
bellard31e31b82003-02-18 22:55:36 +0000587
ths5fafdf22007-09-16 21:08:06 +0000588static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
bellard43fff232003-07-09 19:31:39 +0000589 const target_siginfo_t *info)
590{
591 tswap_siginfo(tinfo, info);
592 return 0;
593}
594
thsc3b5bc82007-12-02 06:31:25 +0000595static inline int current_exec_domain_sig(int sig)
596{
597 return /* current->exec_domain && current->exec_domain->signal_invmap
598 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
599}
600
bellard459a4012007-11-11 19:45:10 +0000601#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000602
603/* from the Linux kernel */
604
605struct target_fpreg {
606 uint16_t significand[4];
607 uint16_t exponent;
608};
609
610struct target_fpxreg {
611 uint16_t significand[4];
612 uint16_t exponent;
613 uint16_t padding[3];
614};
615
616struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000617 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000618};
619
620struct target_fpstate {
621 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000622 abi_ulong cw;
623 abi_ulong sw;
624 abi_ulong tag;
625 abi_ulong ipoff;
626 abi_ulong cssel;
627 abi_ulong dataoff;
628 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000629 struct target_fpreg _st[8];
630 uint16_t status;
631 uint16_t magic; /* 0xffff = regular FPU data only */
632
633 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000634 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
635 abi_ulong mxcsr;
636 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000637 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
638 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000639 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000640};
641
642#define X86_FXSR_MAGIC 0x0000
643
644struct target_sigcontext {
645 uint16_t gs, __gsh;
646 uint16_t fs, __fsh;
647 uint16_t es, __esh;
648 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000649 abi_ulong edi;
650 abi_ulong esi;
651 abi_ulong ebp;
652 abi_ulong esp;
653 abi_ulong ebx;
654 abi_ulong edx;
655 abi_ulong ecx;
656 abi_ulong eax;
657 abi_ulong trapno;
658 abi_ulong err;
659 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000660 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000661 abi_ulong eflags;
662 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000663 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000664 abi_ulong fpstate; /* pointer */
665 abi_ulong oldmask;
666 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000667};
668
bellard66fb9762003-03-23 01:06:05 +0000669struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000670 abi_ulong tuc_flags;
671 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +0000672 target_stack_t tuc_stack;
673 struct target_sigcontext tuc_mcontext;
674 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000675};
676
677struct sigframe
678{
blueswir1992f48a2007-10-14 16:27:31 +0000679 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000680 int sig;
681 struct target_sigcontext sc;
682 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000683 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000684 char retcode[8];
685};
686
687struct rt_sigframe
688{
blueswir1992f48a2007-10-14 16:27:31 +0000689 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000690 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000691 abi_ulong pinfo;
692 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000693 struct target_siginfo info;
694 struct target_ucontext uc;
695 struct target_fpstate fpstate;
696 char retcode[8];
697};
698
699/*
700 * Set up a signal frame.
701 */
702
bellard66fb9762003-03-23 01:06:05 +0000703/* XXX: save x87 state */
704static int
705setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000706 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000707{
708 int err = 0;
bellard775b58d2007-11-11 16:22:17 +0000709 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000710
bellard579a97f2007-11-11 14:26:47 +0000711 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000712 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
713 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
714 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
715 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000716 err |= __put_user(env->regs[R_EDI], &sc->edi);
717 err |= __put_user(env->regs[R_ESI], &sc->esi);
718 err |= __put_user(env->regs[R_EBP], &sc->ebp);
719 err |= __put_user(env->regs[R_ESP], &sc->esp);
720 err |= __put_user(env->regs[R_EBX], &sc->ebx);
721 err |= __put_user(env->regs[R_EDX], &sc->edx);
722 err |= __put_user(env->regs[R_ECX], &sc->ecx);
723 err |= __put_user(env->regs[R_EAX], &sc->eax);
bellard66099dd2003-05-08 15:34:02 +0000724 err |= __put_user(env->exception_index, &sc->trapno);
725 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000726 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000727 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000728 err |= __put_user(env->eflags, &sc->eflags);
729 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000730 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000731
bellard28be6232007-11-11 22:23:38 +0000732 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000733 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000734 magic = 0xffff;
735 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000736 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000737
bellard66fb9762003-03-23 01:06:05 +0000738 /* non-iBCS2 extensions.. */
739 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000740 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000741 return err;
742}
743
744/*
745 * Determine which stack to use..
746 */
747
bellard579a97f2007-11-11 14:26:47 +0000748static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000749get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000750{
751 unsigned long esp;
752
753 /* Default to using normal stack */
754 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000755 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000756 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000757 if (sas_ss_flags(esp) == 0)
758 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
759 }
bellard66fb9762003-03-23 01:06:05 +0000760
761 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000762 else
bellarda52c7572003-06-21 13:14:12 +0000763 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000764 !(ka->sa_flags & TARGET_SA_RESTORER) &&
765 ka->sa_restorer) {
766 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000767 }
bellard579a97f2007-11-11 14:26:47 +0000768 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000769}
770
bellard579a97f2007-11-11 14:26:47 +0000771/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000772static void setup_frame(int sig, struct target_sigaction *ka,
bellard66fb9762003-03-23 01:06:05 +0000773 target_sigset_t *set, CPUX86State *env)
774{
bellard579a97f2007-11-11 14:26:47 +0000775 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000776 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000777 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000778
bellard579a97f2007-11-11 14:26:47 +0000779 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000780
bellard579a97f2007-11-11 14:26:47 +0000781 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000782 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000783
thsc3b5bc82007-12-02 06:31:25 +0000784 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000785 &frame->sig);
786 if (err)
787 goto give_sigsegv;
788
bellard28be6232007-11-11 22:23:38 +0000789 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
790 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000791 if (err)
792 goto give_sigsegv;
793
bellard92319442004-06-19 16:58:13 +0000794 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
795 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
796 goto give_sigsegv;
797 }
bellard66fb9762003-03-23 01:06:05 +0000798
799 /* Set up to return from userspace. If provided, use a stub
800 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000801 if (ka->sa_flags & TARGET_SA_RESTORER) {
802 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000803 } else {
bellard775b58d2007-11-11 16:22:17 +0000804 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000805 abi_ulong retcode_addr;
806 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
807 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000808 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000809 val16 = 0xb858;
810 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000811 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000812 val16 = 0x80cd;
813 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000814 }
815
816 if (err)
817 goto give_sigsegv;
818
819 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000820 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000821 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000822
823 cpu_x86_load_seg(env, R_DS, __USER_DS);
824 cpu_x86_load_seg(env, R_ES, __USER_DS);
825 cpu_x86_load_seg(env, R_SS, __USER_DS);
826 cpu_x86_load_seg(env, R_CS, __USER_CS);
827 env->eflags &= ~TF_MASK;
828
bellard579a97f2007-11-11 14:26:47 +0000829 unlock_user_struct(frame, frame_addr, 1);
830
bellard66fb9762003-03-23 01:06:05 +0000831 return;
832
833give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000834 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000835 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000836 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000837 force_sig(TARGET_SIGSEGV /* , current */);
838}
839
bellard579a97f2007-11-11 14:26:47 +0000840/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000841static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard9de5e442003-03-23 16:49:39 +0000842 target_siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +0000843 target_sigset_t *set, CPUX86State *env)
844{
bellard28be6232007-11-11 22:23:38 +0000845 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000846 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000847 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000848
bellard579a97f2007-11-11 14:26:47 +0000849 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000850
bellard579a97f2007-11-11 14:26:47 +0000851 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000852 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000853
thsc3b5bc82007-12-02 06:31:25 +0000854 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000855 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000856 addr = frame_addr + offsetof(struct rt_sigframe, info);
857 err |= __put_user(addr, &frame->pinfo);
858 addr = frame_addr + offsetof(struct rt_sigframe, uc);
859 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000860 err |= copy_siginfo_to_user(&frame->info, info);
861 if (err)
862 goto give_sigsegv;
863
864 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000865 err |= __put_user(0, &frame->uc.tuc_flags);
866 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000867 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000868 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000869 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000870 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000871 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000872 &frame->uc.tuc_stack.ss_size);
873 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000874 env, set->sig[0],
875 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000876 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000877 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000878 goto give_sigsegv;
879 }
bellard66fb9762003-03-23 01:06:05 +0000880
881 /* Set up to return from userspace. If provided, use a stub
882 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000883 if (ka->sa_flags & TARGET_SA_RESTORER) {
884 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000885 } else {
bellard775b58d2007-11-11 16:22:17 +0000886 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000887 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
888 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000889 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000890 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000891 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000892 val16 = 0x80cd;
893 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000894 }
895
896 if (err)
897 goto give_sigsegv;
898
899 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000900 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000901 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000902
903 cpu_x86_load_seg(env, R_DS, __USER_DS);
904 cpu_x86_load_seg(env, R_ES, __USER_DS);
905 cpu_x86_load_seg(env, R_SS, __USER_DS);
906 cpu_x86_load_seg(env, R_CS, __USER_CS);
907 env->eflags &= ~TF_MASK;
908
bellard579a97f2007-11-11 14:26:47 +0000909 unlock_user_struct(frame, frame_addr, 1);
910
bellard66fb9762003-03-23 01:06:05 +0000911 return;
912
913give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000914 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000915 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000916 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000917 force_sig(TARGET_SIGSEGV /* , current */);
918}
919
920static int
921restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
922{
923 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000924 abi_ulong fpstate_addr;
925 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000926
bellard28be6232007-11-11 22:23:38 +0000927 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
928 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
929 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
930 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +0000931
bellard28be6232007-11-11 22:23:38 +0000932 env->regs[R_EDI] = tswapl(sc->edi);
933 env->regs[R_ESI] = tswapl(sc->esi);
934 env->regs[R_EBP] = tswapl(sc->ebp);
935 env->regs[R_ESP] = tswapl(sc->esp);
936 env->regs[R_EBX] = tswapl(sc->ebx);
937 env->regs[R_EDX] = tswapl(sc->edx);
938 env->regs[R_ECX] = tswapl(sc->ecx);
939 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +0000940
941 cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
942 cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +0000943
bellard28be6232007-11-11 22:23:38 +0000944 tmpflags = tswapl(sc->eflags);
945 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
946 // regs->orig_eax = -1; /* disable syscall checks */
947
948 fpstate_addr = tswapl(sc->fpstate);
949 if (fpstate_addr != 0) {
950 if (!access_ok(VERIFY_READ, fpstate_addr,
951 sizeof(struct target_fpstate)))
952 goto badframe;
953 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000954 }
955
bellard28be6232007-11-11 22:23:38 +0000956 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +0000957 return err;
bellard66fb9762003-03-23 01:06:05 +0000958badframe:
959 return 1;
bellard66fb9762003-03-23 01:06:05 +0000960}
961
962long do_sigreturn(CPUX86State *env)
963{
bellard579a97f2007-11-11 14:26:47 +0000964 struct sigframe *frame;
965 abi_ulong frame_addr = env->regs[R_ESP] - 8;
bellard66fb9762003-03-23 01:06:05 +0000966 target_sigset_t target_set;
967 sigset_t set;
968 int eax, i;
969
bellard447db212003-05-10 15:10:36 +0000970#if defined(DEBUG_SIGNAL)
971 fprintf(stderr, "do_sigreturn\n");
972#endif
bellard579a97f2007-11-11 14:26:47 +0000973 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
974 goto badframe;
bellard66fb9762003-03-23 01:06:05 +0000975 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +0000976 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
977 goto badframe;
978 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
979 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
980 goto badframe;
981 }
bellard66fb9762003-03-23 01:06:05 +0000982
bellard92319442004-06-19 16:58:13 +0000983 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +0000984 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +0000985
bellard66fb9762003-03-23 01:06:05 +0000986 /* restore registers */
987 if (restore_sigcontext(env, &frame->sc, &eax))
988 goto badframe;
bellard579a97f2007-11-11 14:26:47 +0000989 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +0000990 return eax;
991
992badframe:
bellard579a97f2007-11-11 14:26:47 +0000993 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +0000994 force_sig(TARGET_SIGSEGV);
995 return 0;
996}
997
998long do_rt_sigreturn(CPUX86State *env)
999{
bellard28be6232007-11-11 22:23:38 +00001000 abi_ulong frame_addr;
1001 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001002 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001003 int eax;
1004
bellard28be6232007-11-11 22:23:38 +00001005 frame_addr = env->regs[R_ESP] - 4;
1006 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1007 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001008 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +00001009 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001010
bellardb8076a72005-04-07 22:20:31 +00001011 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001012 goto badframe;
1013
bellard28be6232007-11-11 22:23:38 +00001014 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1015 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001016 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001017
bellard28be6232007-11-11 22:23:38 +00001018 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001019 return eax;
1020
1021badframe:
bellard28be6232007-11-11 22:23:38 +00001022 unlock_user_struct(frame, frame_addr, 0);
1023 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001024 return 0;
1025}
1026
bellard43fff232003-07-09 19:31:39 +00001027#elif defined(TARGET_ARM)
1028
1029struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001030 abi_ulong trap_no;
1031 abi_ulong error_code;
1032 abi_ulong oldmask;
1033 abi_ulong arm_r0;
1034 abi_ulong arm_r1;
1035 abi_ulong arm_r2;
1036 abi_ulong arm_r3;
1037 abi_ulong arm_r4;
1038 abi_ulong arm_r5;
1039 abi_ulong arm_r6;
1040 abi_ulong arm_r7;
1041 abi_ulong arm_r8;
1042 abi_ulong arm_r9;
1043 abi_ulong arm_r10;
1044 abi_ulong arm_fp;
1045 abi_ulong arm_ip;
1046 abi_ulong arm_sp;
1047 abi_ulong arm_lr;
1048 abi_ulong arm_pc;
1049 abi_ulong arm_cpsr;
1050 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001051};
1052
pbrooka745ec62008-05-06 15:36:17 +00001053struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001054 abi_ulong tuc_flags;
1055 abi_ulong tuc_link;
bellardb8076a72005-04-07 22:20:31 +00001056 target_stack_t tuc_stack;
1057 struct target_sigcontext tuc_mcontext;
1058 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001059};
1060
pbrooka745ec62008-05-06 15:36:17 +00001061struct target_ucontext_v2 {
1062 abi_ulong tuc_flags;
1063 abi_ulong tuc_link;
1064 target_stack_t tuc_stack;
1065 struct target_sigcontext tuc_mcontext;
1066 target_sigset_t tuc_sigmask; /* mask last for extensibility */
1067 char __unused[128 - sizeof(sigset_t)];
1068 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1069};
1070
pbrooka8c33202008-05-07 23:22:46 +00001071struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001072{
1073 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001074 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1075 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001076};
1077
pbrooka8c33202008-05-07 23:22:46 +00001078struct sigframe_v2
1079{
1080 struct target_ucontext_v2 uc;
1081 abi_ulong retcode;
1082};
1083
pbrooka745ec62008-05-06 15:36:17 +00001084struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001085{
bellardf8b0aa22007-11-11 23:03:42 +00001086 abi_ulong pinfo;
1087 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001088 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001089 struct target_ucontext_v1 uc;
1090 abi_ulong retcode;
1091};
1092
1093struct rt_sigframe_v2
1094{
1095 struct target_siginfo info;
1096 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001097 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001098};
1099
1100#define TARGET_CONFIG_CPU_32 1
1101
1102/*
1103 * For ARM syscalls, we encode the syscall number into the instruction.
1104 */
1105#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1106#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1107
1108/*
1109 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1110 * need two 16-bit instructions.
1111 */
1112#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1113#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1114
blueswir1992f48a2007-10-14 16:27:31 +00001115static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001116 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1117 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1118};
1119
1120
bellard43fff232003-07-09 19:31:39 +00001121#define __get_user_error(x,p,e) __get_user(x, p)
1122
1123static inline int valid_user_regs(CPUState *regs)
1124{
1125 return 1;
1126}
1127
pbrooka8c33202008-05-07 23:22:46 +00001128static void
bellard43fff232003-07-09 19:31:39 +00001129setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
bellardf8b0aa22007-11-11 23:03:42 +00001130 CPUState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001131{
pbrooka8c33202008-05-07 23:22:46 +00001132 __put_user(env->regs[0], &sc->arm_r0);
1133 __put_user(env->regs[1], &sc->arm_r1);
1134 __put_user(env->regs[2], &sc->arm_r2);
1135 __put_user(env->regs[3], &sc->arm_r3);
1136 __put_user(env->regs[4], &sc->arm_r4);
1137 __put_user(env->regs[5], &sc->arm_r5);
1138 __put_user(env->regs[6], &sc->arm_r6);
1139 __put_user(env->regs[7], &sc->arm_r7);
1140 __put_user(env->regs[8], &sc->arm_r8);
1141 __put_user(env->regs[9], &sc->arm_r9);
1142 __put_user(env->regs[10], &sc->arm_r10);
1143 __put_user(env->regs[11], &sc->arm_fp);
1144 __put_user(env->regs[12], &sc->arm_ip);
1145 __put_user(env->regs[13], &sc->arm_sp);
1146 __put_user(env->regs[14], &sc->arm_lr);
1147 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001148#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001149 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001150#endif
1151
pbrooka8c33202008-05-07 23:22:46 +00001152 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1153 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1154 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1155 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001156}
1157
bellard579a97f2007-11-11 14:26:47 +00001158static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00001159get_sigframe(struct target_sigaction *ka, CPUState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001160{
1161 unsigned long sp = regs->regs[13];
1162
bellard43fff232003-07-09 19:31:39 +00001163 /*
1164 * This is the X/Open sanctioned signal stack switching.
1165 */
pbrook624f7972008-05-31 16:11:38 +00001166 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001167 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001168 /*
1169 * ATPCS B01 mandates 8-byte alignment
1170 */
bellard579a97f2007-11-11 14:26:47 +00001171 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001172}
1173
1174static int
pbrook624f7972008-05-31 16:11:38 +00001175setup_return(CPUState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001176 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001177{
pbrook624f7972008-05-31 16:11:38 +00001178 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001179 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001180 int thumb = handler & 1;
bellard43fff232003-07-09 19:31:39 +00001181
pbrook624f7972008-05-31 16:11:38 +00001182 if (ka->sa_flags & TARGET_SA_RESTORER) {
1183 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001184 } else {
1185 unsigned int idx = thumb;
1186
pbrook624f7972008-05-31 16:11:38 +00001187 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001188 idx += 2;
1189
1190 if (__put_user(retcodes[idx], rc))
1191 return 1;
1192#if 0
blueswir1992f48a2007-10-14 16:27:31 +00001193 flush_icache_range((abi_ulong)rc,
1194 (abi_ulong)(rc + 1));
bellard43fff232003-07-09 19:31:39 +00001195#endif
bellardf8b0aa22007-11-11 23:03:42 +00001196 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001197 }
1198
1199 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001200 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001201 env->regs[14] = retcode;
1202 env->regs[15] = handler & (thumb ? ~1 : ~3);
pbrook75b680e2008-03-21 16:07:30 +00001203 env->thumb = thumb;
bellard43fff232003-07-09 19:31:39 +00001204
bellardb5ff1b32005-11-26 10:38:39 +00001205#if 0
bellard43fff232003-07-09 19:31:39 +00001206#ifdef TARGET_CONFIG_CPU_32
1207 env->cpsr = cpsr;
1208#endif
bellardb5ff1b32005-11-26 10:38:39 +00001209#endif
bellard43fff232003-07-09 19:31:39 +00001210
1211 return 0;
1212}
1213
pbrooka8c33202008-05-07 23:22:46 +00001214static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
1215 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001216{
pbrooka8c33202008-05-07 23:22:46 +00001217 struct target_sigaltstack stack;
1218 int i;
1219
1220 /* Clear all the bits of the ucontext we don't use. */
1221 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1222
1223 memset(&stack, 0, sizeof(stack));
1224 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1225 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1226 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1227 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1228
1229 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
1230 /* FIXME: Save coprocessor signal frame. */
1231 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1232 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1233 }
1234}
1235
1236/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001237static void setup_frame_v1(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001238 target_sigset_t *set, CPUState *regs)
1239{
1240 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001241 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001242 int i;
bellard43fff232003-07-09 19:31:39 +00001243
bellard579a97f2007-11-11 14:26:47 +00001244 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1245 return;
1246
pbrooka8c33202008-05-07 23:22:46 +00001247 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001248
bellard92319442004-06-19 16:58:13 +00001249 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1250 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001251 goto end;
bellard43fff232003-07-09 19:31:39 +00001252 }
1253
pbrooka8c33202008-05-07 23:22:46 +00001254 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1255 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001256
1257end:
1258 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001259}
1260
pbrook624f7972008-05-31 16:11:38 +00001261static void setup_frame_v2(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001262 target_sigset_t *set, CPUState *regs)
1263{
1264 struct sigframe_v2 *frame;
1265 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1266
1267 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1268 return;
1269
1270 setup_sigframe_v2(&frame->uc, set, regs);
1271
1272 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1273 frame_addr + offsetof(struct sigframe_v2, retcode));
1274
1275 unlock_user_struct(frame, frame_addr, 1);
1276}
1277
pbrook624f7972008-05-31 16:11:38 +00001278static void setup_frame(int usig, struct target_sigaction *ka,
pbrooka8c33202008-05-07 23:22:46 +00001279 target_sigset_t *set, CPUState *regs)
1280{
1281 if (get_osversion() >= 0x020612) {
1282 setup_frame_v2(usig, ka, set, regs);
1283 } else {
1284 setup_frame_v1(usig, ka, set, regs);
1285 }
bellard43fff232003-07-09 19:31:39 +00001286}
1287
bellard579a97f2007-11-11 14:26:47 +00001288/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001289static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001290 target_siginfo_t *info,
1291 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001292{
pbrooka745ec62008-05-06 15:36:17 +00001293 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001294 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001295 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001296 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001297 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001298
bellard579a97f2007-11-11 14:26:47 +00001299 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001300 return /* 1 */;
1301
pbrooka745ec62008-05-06 15:36:17 +00001302 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001303 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001304 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001305 __put_user(uc_addr, &frame->puc);
1306 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001307
1308 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001309 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001310
thsa04e1342007-09-27 13:57:58 +00001311 memset(&stack, 0, sizeof(stack));
1312 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1313 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1314 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001315 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001316
pbrooka8c33202008-05-07 23:22:46 +00001317 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001318 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001319 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001320 goto end;
bellard92319442004-06-19 16:58:13 +00001321 }
bellard43fff232003-07-09 19:31:39 +00001322
pbrooka8c33202008-05-07 23:22:46 +00001323 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1324 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001325
pbrooka8c33202008-05-07 23:22:46 +00001326 env->regs[1] = info_addr;
1327 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001328
1329end:
1330 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001331}
1332
pbrook624f7972008-05-31 16:11:38 +00001333static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001334 target_siginfo_t *info,
1335 target_sigset_t *set, CPUState *env)
1336{
1337 struct rt_sigframe_v2 *frame;
1338 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001339 abi_ulong info_addr, uc_addr;
1340
1341 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1342 return /* 1 */;
1343
1344 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1345 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001346 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001347
pbrooka8c33202008-05-07 23:22:46 +00001348 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001349
pbrooka8c33202008-05-07 23:22:46 +00001350 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1351 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001352
pbrooka8c33202008-05-07 23:22:46 +00001353 env->regs[1] = info_addr;
1354 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001355
bellard579a97f2007-11-11 14:26:47 +00001356 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001357}
1358
pbrook624f7972008-05-31 16:11:38 +00001359static void setup_rt_frame(int usig, struct target_sigaction *ka,
pbrooka745ec62008-05-06 15:36:17 +00001360 target_siginfo_t *info,
1361 target_sigset_t *set, CPUState *env)
1362{
1363 if (get_osversion() >= 0x020612) {
1364 setup_rt_frame_v2(usig, ka, info, set, env);
1365 } else {
1366 setup_rt_frame_v1(usig, ka, info, set, env);
1367 }
1368}
1369
bellard43fff232003-07-09 19:31:39 +00001370static int
1371restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
1372{
1373 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001374 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001375
1376 __get_user_error(env->regs[0], &sc->arm_r0, err);
1377 __get_user_error(env->regs[1], &sc->arm_r1, err);
1378 __get_user_error(env->regs[2], &sc->arm_r2, err);
1379 __get_user_error(env->regs[3], &sc->arm_r3, err);
1380 __get_user_error(env->regs[4], &sc->arm_r4, err);
1381 __get_user_error(env->regs[5], &sc->arm_r5, err);
1382 __get_user_error(env->regs[6], &sc->arm_r6, err);
1383 __get_user_error(env->regs[7], &sc->arm_r7, err);
1384 __get_user_error(env->regs[8], &sc->arm_r8, err);
1385 __get_user_error(env->regs[9], &sc->arm_r9, err);
1386 __get_user_error(env->regs[10], &sc->arm_r10, err);
1387 __get_user_error(env->regs[11], &sc->arm_fp, err);
1388 __get_user_error(env->regs[12], &sc->arm_ip, err);
1389 __get_user_error(env->regs[13], &sc->arm_sp, err);
1390 __get_user_error(env->regs[14], &sc->arm_lr, err);
1391 __get_user_error(env->regs[15], &sc->arm_pc, err);
1392#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001393 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001394 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001395#endif
1396
1397 err |= !valid_user_regs(env);
1398
1399 return err;
1400}
1401
aurel32dc7eea62009-01-30 20:15:32 +00001402static long do_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001403{
bellardf8b0aa22007-11-11 23:03:42 +00001404 abi_ulong frame_addr;
pbrooka8c33202008-05-07 23:22:46 +00001405 struct sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001406 target_sigset_t set;
1407 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001408 int i;
bellard43fff232003-07-09 19:31:39 +00001409
1410 /*
1411 * Since we stacked the signal on a 64-bit boundary,
1412 * then 'sp' should be word aligned here. If it's
1413 * not, then the user is trying to mess with us.
1414 */
1415 if (env->regs[13] & 7)
1416 goto badframe;
1417
bellardf8b0aa22007-11-11 23:03:42 +00001418 frame_addr = env->regs[13];
1419 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1420 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001421
bellard92319442004-06-19 16:58:13 +00001422 if (__get_user(set.sig[0], &frame->sc.oldmask))
1423 goto badframe;
1424 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1425 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1426 goto badframe;
1427 }
bellard43fff232003-07-09 19:31:39 +00001428
bellard92319442004-06-19 16:58:13 +00001429 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001430 sigprocmask(SIG_SETMASK, &host_set, NULL);
1431
1432 if (restore_sigcontext(env, &frame->sc))
1433 goto badframe;
1434
1435#if 0
1436 /* Send SIGTRAP if we're single-stepping */
1437 if (ptrace_cancel_bpt(current))
1438 send_sig(SIGTRAP, current, 1);
1439#endif
bellardf8b0aa22007-11-11 23:03:42 +00001440 unlock_user_struct(frame, frame_addr, 0);
1441 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001442
1443badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001444 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001445 force_sig(SIGSEGV /* , current */);
1446 return 0;
1447}
1448
pbrooka8c33202008-05-07 23:22:46 +00001449static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr,
1450 struct target_ucontext_v2 *uc)
1451{
1452 sigset_t host_set;
1453
1454 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1455 sigprocmask(SIG_SETMASK, &host_set, NULL);
1456
1457 if (restore_sigcontext(env, &uc->tuc_mcontext))
1458 return 1;
1459
1460 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1461 return 1;
1462
1463#if 0
1464 /* Send SIGTRAP if we're single-stepping */
1465 if (ptrace_cancel_bpt(current))
1466 send_sig(SIGTRAP, current, 1);
1467#endif
1468
1469 return 0;
1470}
1471
aurel32dc7eea62009-01-30 20:15:32 +00001472static long do_sigreturn_v2(CPUState *env)
pbrooka8c33202008-05-07 23:22:46 +00001473{
1474 abi_ulong frame_addr;
1475 struct sigframe_v2 *frame;
1476
1477 /*
1478 * Since we stacked the signal on a 64-bit boundary,
1479 * then 'sp' should be word aligned here. If it's
1480 * not, then the user is trying to mess with us.
1481 */
1482 if (env->regs[13] & 7)
1483 goto badframe;
1484
1485 frame_addr = env->regs[13];
1486 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1487 goto badframe;
1488
1489 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1490 goto badframe;
1491
1492 unlock_user_struct(frame, frame_addr, 0);
1493 return env->regs[0];
1494
1495badframe:
1496 unlock_user_struct(frame, frame_addr, 0);
1497 force_sig(SIGSEGV /* , current */);
1498 return 0;
1499}
1500
1501long do_sigreturn(CPUState *env)
1502{
1503 if (get_osversion() >= 0x020612) {
1504 return do_sigreturn_v2(env);
1505 } else {
1506 return do_sigreturn_v1(env);
1507 }
1508}
1509
aurel32dc7eea62009-01-30 20:15:32 +00001510static long do_rt_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001511{
bellardf8b0aa22007-11-11 23:03:42 +00001512 abi_ulong frame_addr;
pbrooka745ec62008-05-06 15:36:17 +00001513 struct rt_sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001514 sigset_t host_set;
1515
1516 /*
1517 * Since we stacked the signal on a 64-bit boundary,
1518 * then 'sp' should be word aligned here. If it's
1519 * not, then the user is trying to mess with us.
1520 */
1521 if (env->regs[13] & 7)
1522 goto badframe;
1523
bellardf8b0aa22007-11-11 23:03:42 +00001524 frame_addr = env->regs[13];
1525 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1526 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001527
bellardb8076a72005-04-07 22:20:31 +00001528 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00001529 sigprocmask(SIG_SETMASK, &host_set, NULL);
1530
bellardb8076a72005-04-07 22:20:31 +00001531 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00001532 goto badframe;
1533
pbrooka745ec62008-05-06 15:36:17 +00001534 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 +00001535 goto badframe;
1536
bellard43fff232003-07-09 19:31:39 +00001537#if 0
1538 /* Send SIGTRAP if we're single-stepping */
1539 if (ptrace_cancel_bpt(current))
1540 send_sig(SIGTRAP, current, 1);
1541#endif
bellardf8b0aa22007-11-11 23:03:42 +00001542 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001543 return env->regs[0];
1544
1545badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001546 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001547 force_sig(SIGSEGV /* , current */);
1548 return 0;
1549}
1550
aurel32dc7eea62009-01-30 20:15:32 +00001551static long do_rt_sigreturn_v2(CPUState *env)
pbrooka745ec62008-05-06 15:36:17 +00001552{
1553 abi_ulong frame_addr;
1554 struct rt_sigframe_v2 *frame;
pbrooka745ec62008-05-06 15:36:17 +00001555
1556 /*
1557 * Since we stacked the signal on a 64-bit boundary,
1558 * then 'sp' should be word aligned here. If it's
1559 * not, then the user is trying to mess with us.
1560 */
1561 if (env->regs[13] & 7)
1562 goto badframe;
1563
1564 frame_addr = env->regs[13];
1565 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1566 goto badframe;
1567
pbrooka8c33202008-05-07 23:22:46 +00001568 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1569 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00001570
pbrooka745ec62008-05-06 15:36:17 +00001571 unlock_user_struct(frame, frame_addr, 0);
1572 return env->regs[0];
1573
1574badframe:
1575 unlock_user_struct(frame, frame_addr, 0);
1576 force_sig(SIGSEGV /* , current */);
1577 return 0;
1578}
1579
1580long do_rt_sigreturn(CPUState *env)
1581{
1582 if (get_osversion() >= 0x020612) {
1583 return do_rt_sigreturn_v2(env);
1584 } else {
1585 return do_rt_sigreturn_v1(env);
1586 }
1587}
1588
bellard6d5e2162004-09-30 22:04:13 +00001589#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00001590
bellard6d5e2162004-09-30 22:04:13 +00001591#define __SUNOS_MAXWIN 31
1592
1593/* This is what SunOS does, so shall I. */
1594struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001595 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00001596
blueswir1992f48a2007-10-14 16:27:31 +00001597 abi_ulong sigc_mask; /* sigmask to restore */
1598 abi_ulong sigc_sp; /* stack pointer */
1599 abi_ulong sigc_pc; /* program counter */
1600 abi_ulong sigc_npc; /* next program counter */
1601 abi_ulong sigc_psr; /* for condition codes etc */
1602 abi_ulong sigc_g1; /* User uses these two registers */
1603 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00001604
1605 /* Now comes information regarding the users window set
1606 * at the time of the signal.
1607 */
blueswir1992f48a2007-10-14 16:27:31 +00001608 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00001609
1610 /* stack ptrs for each regwin buf */
1611 char *sigc_spbuf[__SUNOS_MAXWIN];
1612
1613 /* Windows to restore after signal */
1614 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001615 abi_ulong locals[8];
1616 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00001617 } sigc_wbuf[__SUNOS_MAXWIN];
1618};
1619/* A Sparc stack frame */
1620struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00001621 abi_ulong locals[8];
1622 abi_ulong ins[6];
bellard6d5e2162004-09-30 22:04:13 +00001623 struct sparc_stackf *fp;
blueswir1992f48a2007-10-14 16:27:31 +00001624 abi_ulong callers_pc;
bellard6d5e2162004-09-30 22:04:13 +00001625 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00001626 abi_ulong xargs[6];
1627 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00001628};
1629
1630typedef struct {
1631 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001632 abi_ulong psr;
1633 abi_ulong pc;
1634 abi_ulong npc;
1635 abi_ulong y;
1636 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00001637 } si_regs;
1638 int si_mask;
1639} __siginfo_t;
1640
1641typedef struct {
1642 unsigned long si_float_regs [32];
1643 unsigned long si_fsr;
1644 unsigned long si_fpqdepth;
1645 struct {
1646 unsigned long *insn_addr;
1647 unsigned long insn;
1648 } si_fpqueue [16];
bellard74ccb342006-07-18 21:23:34 +00001649} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00001650
1651
1652struct target_signal_frame {
1653 struct sparc_stackf ss;
1654 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00001655 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00001656 abi_ulong insns[2] __attribute__ ((aligned (8)));
1657 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
1658 abi_ulong extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001659 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001660};
1661struct target_rt_signal_frame {
1662 struct sparc_stackf ss;
1663 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00001664 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00001665 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00001666 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00001667 unsigned int insns[2];
1668 stack_t stack;
1669 unsigned int extra_size; /* Should be 0 */
bellard74ccb342006-07-18 21:23:34 +00001670 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001671};
1672
bellarde80cfcf2004-12-19 23:18:01 +00001673#define UREG_O0 16
1674#define UREG_O6 22
1675#define UREG_I0 0
1676#define UREG_I1 1
1677#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00001678#define UREG_I3 3
1679#define UREG_I4 4
1680#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00001681#define UREG_I6 6
1682#define UREG_I7 7
1683#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00001684#define UREG_FP UREG_I6
1685#define UREG_SP UREG_O6
1686
pbrook624f7972008-05-31 16:11:38 +00001687static inline abi_ulong get_sigframe(struct target_sigaction *sa,
bellard459a4012007-11-11 19:45:10 +00001688 CPUState *env, unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00001689{
bellard459a4012007-11-11 19:45:10 +00001690 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00001691
1692 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00001693
1694 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00001695 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00001696 if (!on_sig_stack(sp)
1697 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
1698 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00001699 }
bellard459a4012007-11-11 19:45:10 +00001700 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00001701}
1702
1703static int
blueswir1992f48a2007-10-14 16:27:31 +00001704setup___siginfo(__siginfo_t *si, CPUState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00001705{
1706 int err = 0, i;
1707
bellard6d5e2162004-09-30 22:04:13 +00001708 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00001709 err |= __put_user(env->pc, &si->si_regs.pc);
1710 err |= __put_user(env->npc, &si->si_regs.npc);
1711 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001712 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00001713 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
1714 }
bellarda315a142005-01-30 22:59:18 +00001715 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001716 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00001717 }
bellard6d5e2162004-09-30 22:04:13 +00001718 err |= __put_user(mask, &si->si_mask);
1719 return err;
1720}
bellarde80cfcf2004-12-19 23:18:01 +00001721
bellard80a9d032005-01-03 23:31:27 +00001722#if 0
bellard6d5e2162004-09-30 22:04:13 +00001723static int
1724setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
1725 CPUState *env, unsigned long mask)
1726{
1727 int err = 0;
1728
1729 err |= __put_user(mask, &sc->sigc_mask);
1730 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
1731 err |= __put_user(env->pc, &sc->sigc_pc);
1732 err |= __put_user(env->npc, &sc->sigc_npc);
1733 err |= __put_user(env->psr, &sc->sigc_psr);
1734 err |= __put_user(env->gregs[1], &sc->sigc_g1);
1735 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
1736
1737 return err;
1738}
bellard80a9d032005-01-03 23:31:27 +00001739#endif
bellard6d5e2162004-09-30 22:04:13 +00001740#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
1741
pbrook624f7972008-05-31 16:11:38 +00001742static void setup_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001743 target_sigset_t *set, CPUState *env)
1744{
bellard459a4012007-11-11 19:45:10 +00001745 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001746 struct target_signal_frame *sf;
1747 int sigframe_size, err, i;
1748
1749 /* 1. Make sure everything is clean */
1750 //synchronize_user_stack();
1751
1752 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00001753 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00001754
bellard459a4012007-11-11 19:45:10 +00001755 sf = lock_user(VERIFY_WRITE, sf_addr,
1756 sizeof(struct target_signal_frame), 0);
1757 if (!sf)
1758 goto sigsegv;
1759
bellarde80cfcf2004-12-19 23:18:01 +00001760 //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 +00001761#if 0
1762 if (invalid_frame_pointer(sf, sigframe_size))
1763 goto sigill_and_return;
1764#endif
1765 /* 2. Save the current process state */
1766 err = setup___siginfo(&sf->info, env, set->sig[0]);
1767 err |= __put_user(0, &sf->extra_size);
1768
1769 //err |= save_fpu_state(regs, &sf->fpu_state);
1770 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
1771
1772 err |= __put_user(set->sig[0], &sf->info.si_mask);
1773 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
1774 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
1775 }
1776
bellarda315a142005-01-30 22:59:18 +00001777 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001778 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00001779 }
bellarda315a142005-01-30 22:59:18 +00001780 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001781 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00001782 }
bellard6d5e2162004-09-30 22:04:13 +00001783 if (err)
1784 goto sigsegv;
1785
1786 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00001787 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001788 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00001789 env->regwptr[UREG_I1] = sf_addr +
1790 offsetof(struct target_signal_frame, info);
1791 env->regwptr[UREG_I2] = sf_addr +
1792 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00001793
1794 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00001795 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00001796 env->npc = (env->pc + 4);
1797 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00001798 if (ka->sa_restorer)
1799 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00001800 else {
bellard775b58d2007-11-11 16:22:17 +00001801 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00001802
1803 env->regwptr[UREG_I7] = sf_addr +
1804 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00001805
1806 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00001807 val32 = 0x821020d8;
1808 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00001809
1810 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00001811 val32 = 0x91d02010;
1812 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00001813 if (err)
1814 goto sigsegv;
1815
1816 /* Flush instruction space. */
1817 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00001818 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00001819 }
bellard459a4012007-11-11 19:45:10 +00001820 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001821 return;
bellard459a4012007-11-11 19:45:10 +00001822#if 0
1823sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00001824 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00001825#endif
bellard6d5e2162004-09-30 22:04:13 +00001826sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00001827 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00001828 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00001829 force_sig(TARGET_SIGSEGV);
1830}
1831static inline int
bellard74ccb342006-07-18 21:23:34 +00001832restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00001833{
1834 int err;
1835#if 0
1836#ifdef CONFIG_SMP
1837 if (current->flags & PF_USEDFPU)
1838 regs->psr &= ~PSR_EF;
1839#else
1840 if (current == last_task_used_math) {
1841 last_task_used_math = 0;
1842 regs->psr &= ~PSR_EF;
1843 }
1844#endif
1845 current->used_math = 1;
1846 current->flags &= ~PF_USEDFPU;
1847#endif
1848#if 0
1849 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
1850 return -EFAULT;
1851#endif
1852
bellardfafffae2006-10-28 12:09:16 +00001853#if 0
1854 /* XXX: incorrect */
bellard6d5e2162004-09-30 22:04:13 +00001855 err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
1856 (sizeof(unsigned long) * 32));
bellardfafffae2006-10-28 12:09:16 +00001857#endif
bellard6d5e2162004-09-30 22:04:13 +00001858 err |= __get_user(env->fsr, &fpu->si_fsr);
1859#if 0
1860 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
1861 if (current->thread.fpqdepth != 0)
1862 err |= __copy_from_user(&current->thread.fpqueue[0],
1863 &fpu->si_fpqueue[0],
1864 ((sizeof(unsigned long) +
1865 (sizeof(unsigned long *)))*16));
1866#endif
1867 return err;
1868}
1869
1870
pbrook624f7972008-05-31 16:11:38 +00001871static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard6d5e2162004-09-30 22:04:13 +00001872 target_siginfo_t *info,
1873 target_sigset_t *set, CPUState *env)
1874{
1875 fprintf(stderr, "setup_rt_frame: not implemented\n");
1876}
1877
1878long do_sigreturn(CPUState *env)
1879{
bellardf8b0aa22007-11-11 23:03:42 +00001880 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001881 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00001882 uint32_t up_psr, pc, npc;
bellard6d5e2162004-09-30 22:04:13 +00001883 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00001884 sigset_t host_set;
bellardf8b0aa22007-11-11 23:03:42 +00001885 abi_ulong fpu_save_addr;
bellarde80cfcf2004-12-19 23:18:01 +00001886 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00001887
bellardf8b0aa22007-11-11 23:03:42 +00001888 sf_addr = env->regwptr[UREG_FP];
1889 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
1890 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00001891#if 0
bellarde80cfcf2004-12-19 23:18:01 +00001892 fprintf(stderr, "sigreturn\n");
1893 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 +00001894#endif
bellarde80cfcf2004-12-19 23:18:01 +00001895 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00001896
1897 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00001898
bellardf8b0aa22007-11-11 23:03:42 +00001899 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00001900 goto segv_and_exit;
1901
1902 err = __get_user(pc, &sf->info.si_regs.pc);
1903 err |= __get_user(npc, &sf->info.si_regs.npc);
1904
bellard6d5e2162004-09-30 22:04:13 +00001905 if ((pc | npc) & 3)
1906 goto segv_and_exit;
1907
1908 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00001909 err |= __get_user(up_psr, &sf->info.si_regs.psr);
1910
bellard6d5e2162004-09-30 22:04:13 +00001911 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00001912 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
1913 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
1914
1915 env->pc = pc;
1916 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00001917 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001918 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001919 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
1920 }
bellarda315a142005-01-30 22:59:18 +00001921 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001922 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
1923 }
bellard6d5e2162004-09-30 22:04:13 +00001924
bellardf8b0aa22007-11-11 23:03:42 +00001925 err |= __get_user(fpu_save_addr, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001926
bellarde80cfcf2004-12-19 23:18:01 +00001927 //if (fpu_save)
1928 // err |= restore_fpu_state(env, fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00001929
1930 /* This is pretty much atomic, no amount locking would prevent
1931 * the races which exist anyways.
1932 */
1933 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00001934 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1935 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
1936 }
1937
1938 target_to_host_sigset_internal(&host_set, &set);
1939 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00001940
1941 if (err)
1942 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00001943 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001944 return env->regwptr[0];
1945
1946segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00001947 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00001948 force_sig(TARGET_SIGSEGV);
1949}
1950
1951long do_rt_sigreturn(CPUState *env)
1952{
1953 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00001954 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00001955}
1956
bellard459a4012007-11-11 19:45:10 +00001957#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00001958#define MC_TSTATE 0
1959#define MC_PC 1
1960#define MC_NPC 2
1961#define MC_Y 3
1962#define MC_G1 4
1963#define MC_G2 5
1964#define MC_G3 6
1965#define MC_G4 7
1966#define MC_G5 8
1967#define MC_G6 9
1968#define MC_G7 10
1969#define MC_O0 11
1970#define MC_O1 12
1971#define MC_O2 13
1972#define MC_O3 14
1973#define MC_O4 15
1974#define MC_O5 16
1975#define MC_O6 17
1976#define MC_O7 18
1977#define MC_NGREG 19
1978
blueswir1992f48a2007-10-14 16:27:31 +00001979typedef abi_ulong target_mc_greg_t;
blueswir15bfb56b2007-10-05 17:01:51 +00001980typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
1981
1982struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00001983 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00001984 uint32_t mcfq_insn;
1985};
1986
1987struct target_mc_fpu {
1988 union {
1989 uint32_t sregs[32];
1990 uint64_t dregs[32];
1991 //uint128_t qregs[16];
1992 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00001993 abi_ulong mcfpu_fsr;
1994 abi_ulong mcfpu_fprs;
1995 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00001996 struct target_mc_fq *mcfpu_fq;
1997 unsigned char mcfpu_qcnt;
1998 unsigned char mcfpu_qentsz;
1999 unsigned char mcfpu_enab;
2000};
2001typedef struct target_mc_fpu target_mc_fpu_t;
2002
2003typedef struct {
2004 target_mc_gregset_t mc_gregs;
2005 target_mc_greg_t mc_fp;
2006 target_mc_greg_t mc_i7;
2007 target_mc_fpu_t mc_fpregs;
2008} target_mcontext_t;
2009
2010struct target_ucontext {
2011 struct target_ucontext *uc_link;
blueswir1992f48a2007-10-14 16:27:31 +00002012 abi_ulong uc_flags;
blueswir15bfb56b2007-10-05 17:01:51 +00002013 target_sigset_t uc_sigmask;
2014 target_mcontext_t uc_mcontext;
2015};
2016
2017/* A V9 register window */
2018struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002019 abi_ulong locals[8];
2020 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002021};
2022
2023#define TARGET_STACK_BIAS 2047
2024
2025/* {set, get}context() needed for 64-bit SparcLinux userland. */
2026void sparc64_set_context(CPUSPARCState *env)
2027{
bellard459a4012007-11-11 19:45:10 +00002028 abi_ulong ucp_addr;
2029 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00002030 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002031 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002032 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002033 unsigned char fenab;
2034 int err;
2035 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002036
bellard459a4012007-11-11 19:45:10 +00002037 ucp_addr = env->regwptr[UREG_I0];
2038 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2039 goto do_sigsegv;
blueswir15bfb56b2007-10-05 17:01:51 +00002040 grp = &ucp->uc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002041 err = __get_user(pc, &((*grp)[MC_PC]));
2042 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002043 if (err || ((pc | npc) & 3))
2044 goto do_sigsegv;
2045 if (env->regwptr[UREG_I1]) {
2046 target_sigset_t target_set;
2047 sigset_t set;
2048
2049 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002050 if (__get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002051 goto do_sigsegv;
2052 } else {
bellard459a4012007-11-11 19:45:10 +00002053 abi_ulong *src, *dst;
2054 src = ucp->uc_sigmask.sig;
2055 dst = target_set.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002056 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002057 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002058 err |= __get_user(*dst, src);
blueswir15bfb56b2007-10-05 17:01:51 +00002059 if (err)
2060 goto do_sigsegv;
2061 }
2062 target_to_host_sigset_internal(&set, &target_set);
2063 sigprocmask(SIG_SETMASK, &set, NULL);
2064 }
2065 env->pc = pc;
2066 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002067 err |= __get_user(env->y, &((*grp)[MC_Y]));
2068 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002069 env->asi = (tstate >> 24) & 0xff;
2070 PUT_CCR(env, tstate >> 32);
2071 PUT_CWP64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002072 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2073 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2074 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2075 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2076 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2077 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2078 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2079 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2080 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2081 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2082 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2083 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2084 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2085 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2086 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002087
bellard579a97f2007-11-11 14:26:47 +00002088 err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp));
2089 err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002090
bellard459a4012007-11-11 19:45:10 +00002091 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2092 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2093 abi_ulong) != 0)
2094 goto do_sigsegv;
2095 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2096 abi_ulong) != 0)
2097 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002098 err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
2099 err |= __get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002100 {
2101 uint32_t *src, *dst;
2102 src = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2103 dst = env->fpr;
2104 /* XXX: check that the CPU storage is the same as user context */
2105 for (i = 0; i < 64; i++, dst++, src++)
2106 err |= __get_user(*dst, src);
2107 }
bellard579a97f2007-11-11 14:26:47 +00002108 err |= __get_user(env->fsr,
2109 &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
2110 err |= __get_user(env->gsr,
2111 &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002112 if (err)
2113 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002114 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002115 return;
2116 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002117 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002118 force_sig(SIGSEGV);
2119}
2120
2121void sparc64_get_context(CPUSPARCState *env)
2122{
bellard459a4012007-11-11 19:45:10 +00002123 abi_ulong ucp_addr;
2124 struct target_ucontext *ucp;
blueswir15bfb56b2007-10-05 17:01:51 +00002125 target_mc_gregset_t *grp;
2126 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002127 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002128 int err;
2129 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002130 target_sigset_t target_set;
2131 sigset_t set;
2132
bellard459a4012007-11-11 19:45:10 +00002133 ucp_addr = env->regwptr[UREG_I0];
2134 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2135 goto do_sigsegv;
2136
blueswir15bfb56b2007-10-05 17:01:51 +00002137 mcp = &ucp->uc_mcontext;
2138 grp = &mcp->mc_gregs;
2139
2140 /* Skip over the trap instruction, first. */
2141 env->pc = env->npc;
2142 env->npc += 4;
2143
2144 err = 0;
2145
2146 sigprocmask(0, NULL, &set);
2147 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002148 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002149 err |= __put_user(target_set.sig[0],
2150 (abi_ulong *)&ucp->uc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002151 } else {
2152 abi_ulong *src, *dst;
2153 src = target_set.sig;
2154 dst = ucp->uc_sigmask.sig;
blueswir1992f48a2007-10-14 16:27:31 +00002155 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002156 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002157 err |= __put_user(*src, dst);
blueswir15bfb56b2007-10-05 17:01:51 +00002158 if (err)
2159 goto do_sigsegv;
2160 }
2161
bellard459a4012007-11-11 19:45:10 +00002162 /* XXX: tstate must be saved properly */
2163 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002164 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2165 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2166 err |= __put_user(env->y, &((*grp)[MC_Y]));
2167 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2168 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2169 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2170 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2171 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2172 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2173 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2174 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2175 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2176 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2177 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2178 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2179 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2180 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2181 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002182
bellard459a4012007-11-11 19:45:10 +00002183 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2184 fp = i7 = 0;
2185 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2186 abi_ulong) != 0)
2187 goto do_sigsegv;
2188 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2189 abi_ulong) != 0)
2190 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002191 err |= __put_user(fp, &(mcp->mc_fp));
2192 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002193
bellard459a4012007-11-11 19:45:10 +00002194 {
2195 uint32_t *src, *dst;
2196 src = env->fpr;
2197 dst = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2198 /* XXX: check that the CPU storage is the same as user context */
2199 for (i = 0; i < 64; i++, dst++, src++)
2200 err |= __put_user(*src, dst);
2201 }
bellard579a97f2007-11-11 14:26:47 +00002202 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2203 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2204 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002205
2206 if (err)
2207 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002208 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002209 return;
2210 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002211 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002212 force_sig(SIGSEGV);
2213}
2214#endif
thsd26bc212007-11-08 18:05:37 +00002215#elif defined(TARGET_ABI_MIPSN64)
ths540635b2007-09-30 01:58:33 +00002216
2217# warning signal handling not implemented
2218
pbrook624f7972008-05-31 16:11:38 +00002219static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002220 target_sigset_t *set, CPUState *env)
2221{
2222 fprintf(stderr, "setup_frame: not implemented\n");
2223}
2224
pbrook624f7972008-05-31 16:11:38 +00002225static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002226 target_siginfo_t *info,
2227 target_sigset_t *set, CPUState *env)
2228{
2229 fprintf(stderr, "setup_rt_frame: not implemented\n");
2230}
2231
2232long do_sigreturn(CPUState *env)
2233{
2234 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002235 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002236}
2237
2238long do_rt_sigreturn(CPUState *env)
2239{
2240 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002241 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002242}
2243
thsd26bc212007-11-08 18:05:37 +00002244#elif defined(TARGET_ABI_MIPSN32)
ths540635b2007-09-30 01:58:33 +00002245
2246# warning signal handling not implemented
2247
pbrook624f7972008-05-31 16:11:38 +00002248static void setup_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002249 target_sigset_t *set, CPUState *env)
2250{
2251 fprintf(stderr, "setup_frame: not implemented\n");
2252}
2253
pbrook624f7972008-05-31 16:11:38 +00002254static void setup_rt_frame(int sig, struct target_sigaction *ka,
ths540635b2007-09-30 01:58:33 +00002255 target_siginfo_t *info,
2256 target_sigset_t *set, CPUState *env)
2257{
2258 fprintf(stderr, "setup_rt_frame: not implemented\n");
2259}
2260
2261long do_sigreturn(CPUState *env)
2262{
2263 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002264 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002265}
2266
2267long do_rt_sigreturn(CPUState *env)
2268{
2269 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002270 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002271}
2272
thsd26bc212007-11-08 18:05:37 +00002273#elif defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002274
2275struct target_sigcontext {
2276 uint32_t sc_regmask; /* Unused */
2277 uint32_t sc_status;
2278 uint64_t sc_pc;
2279 uint64_t sc_regs[32];
2280 uint64_t sc_fpregs[32];
2281 uint32_t sc_ownedfp; /* Unused */
2282 uint32_t sc_fpc_csr;
2283 uint32_t sc_fpc_eir; /* Unused */
2284 uint32_t sc_used_math;
2285 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
2286 uint64_t sc_mdhi;
2287 uint64_t sc_mdlo;
2288 target_ulong sc_hi1; /* Was sc_cause */
2289 target_ulong sc_lo1; /* Was sc_badvaddr */
2290 target_ulong sc_hi2; /* Was sc_sigset[4] */
2291 target_ulong sc_lo2;
2292 target_ulong sc_hi3;
2293 target_ulong sc_lo3;
2294};
2295
2296struct sigframe {
2297 uint32_t sf_ass[4]; /* argument save space for o32 */
2298 uint32_t sf_code[2]; /* signal trampoline */
2299 struct target_sigcontext sf_sc;
2300 target_sigset_t sf_mask;
2301};
2302
2303/* Install trampoline to jump back from signal handler */
2304static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2305{
2306 int err;
2307
2308 /*
2309 * Set up the return code ...
2310 *
2311 * li v0, __NR__foo_sigreturn
2312 * syscall
2313 */
2314
2315 err = __put_user(0x24020000 + syscall, tramp + 0);
2316 err |= __put_user(0x0000000c , tramp + 1);
2317 /* flush_cache_sigtramp((unsigned long) tramp); */
2318 return err;
2319}
2320
2321static inline int
2322setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2323{
2324 int err = 0;
2325
thsb5dc7732008-06-27 10:02:35 +00002326 err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002327
thsb5dc7732008-06-27 10:02:35 +00002328#define save_gp_reg(i) do { \
2329 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002330 } while(0)
2331 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
2332 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
2333 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
2334 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
2335 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
2336 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
2337 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
2338 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
2339 save_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002340#undef save_gp_reg
bellard106ec872006-06-27 21:08:10 +00002341
thsb5dc7732008-06-27 10:02:35 +00002342 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2343 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002344
2345 /* Not used yet, but might be useful if we ever have DSP suppport */
2346#if 0
2347 if (cpu_has_dsp) {
2348 err |= __put_user(mfhi1(), &sc->sc_hi1);
2349 err |= __put_user(mflo1(), &sc->sc_lo1);
2350 err |= __put_user(mfhi2(), &sc->sc_hi2);
2351 err |= __put_user(mflo2(), &sc->sc_lo2);
2352 err |= __put_user(mfhi3(), &sc->sc_hi3);
2353 err |= __put_user(mflo3(), &sc->sc_lo3);
2354 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2355 }
2356 /* same with 64 bit */
ths388bb212007-05-13 13:58:00 +00002357#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002358 err |= __put_user(regs->hi, &sc->sc_hi[0]);
2359 err |= __put_user(regs->lo, &sc->sc_lo[0]);
2360 if (cpu_has_dsp) {
2361 err |= __put_user(mfhi1(), &sc->sc_hi[1]);
2362 err |= __put_user(mflo1(), &sc->sc_lo[1]);
2363 err |= __put_user(mfhi2(), &sc->sc_hi[2]);
2364 err |= __put_user(mflo2(), &sc->sc_lo[2]);
2365 err |= __put_user(mfhi3(), &sc->sc_hi[3]);
2366 err |= __put_user(mflo3(), &sc->sc_lo[3]);
2367 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2368 }
ths388bb212007-05-13 13:58:00 +00002369#endif
2370#endif
bellard106ec872006-06-27 21:08:10 +00002371
ths388bb212007-05-13 13:58:00 +00002372#if 0
bellard106ec872006-06-27 21:08:10 +00002373 err |= __put_user(!!used_math(), &sc->sc_used_math);
2374
2375 if (!used_math())
2376 goto out;
2377
2378 /*
2379 * Save FPU state to signal context. Signal handler will "inherit"
2380 * current FPU state.
2381 */
2382 preempt_disable();
2383
2384 if (!is_fpu_owner()) {
2385 own_fpu();
2386 restore_fp(current);
2387 }
2388 err |= save_fp_context(sc);
2389
2390 preempt_enable();
2391 out:
2392#endif
2393 return err;
2394}
2395
2396static inline int
2397restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2398{
2399 int err = 0;
2400
2401 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2402
thsb5dc7732008-06-27 10:02:35 +00002403 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2404 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002405
thsead93602007-09-06 00:18:15 +00002406#define restore_gp_reg(i) do { \
thsb5dc7732008-06-27 10:02:35 +00002407 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002408 } while(0)
2409 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
2410 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
2411 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
2412 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
2413 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
2414 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
2415 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
2416 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
2417 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
2418 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
2419 restore_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002420#undef restore_gp_reg
bellard106ec872006-06-27 21:08:10 +00002421
2422#if 0
2423 if (cpu_has_dsp) {
2424 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
2425 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
2426 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
2427 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
2428 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
2429 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2430 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2431 }
ths388bb212007-05-13 13:58:00 +00002432#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002433 err |= __get_user(regs->hi, &sc->sc_hi[0]);
2434 err |= __get_user(regs->lo, &sc->sc_lo[0]);
2435 if (cpu_has_dsp) {
2436 err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
2437 err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
2438 err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
2439 err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
2440 err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
2441 err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
2442 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2443 }
ths388bb212007-05-13 13:58:00 +00002444#endif
bellard106ec872006-06-27 21:08:10 +00002445
2446 err |= __get_user(used_math, &sc->sc_used_math);
2447 conditional_used_math(used_math);
2448
2449 preempt_disable();
2450
2451 if (used_math()) {
2452 /* restore fpu context if we have used it before */
2453 own_fpu();
2454 err |= restore_fp_context(sc);
2455 } else {
2456 /* signal handler may have used FPU. Give it up. */
2457 lose_fpu();
2458 }
2459
2460 preempt_enable();
2461#endif
2462 return err;
2463}
2464/*
2465 * Determine which stack to use..
2466 */
bellard579a97f2007-11-11 14:26:47 +00002467static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00002468get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002469{
2470 unsigned long sp;
2471
2472 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002473 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002474
2475 /*
2476 * FPU emulator may have it's own trampoline active just
2477 * above the user stack, 16-bytes before the next lowest
2478 * 16 byte boundary. Try to avoid trashing it.
2479 */
2480 sp -= 32;
2481
bellard106ec872006-06-27 21:08:10 +00002482 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002483 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002484 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2485 }
bellard106ec872006-06-27 21:08:10 +00002486
bellard579a97f2007-11-11 14:26:47 +00002487 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002488}
2489
bellard579a97f2007-11-11 14:26:47 +00002490/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002491static void setup_frame(int sig, struct target_sigaction * ka,
bellard579a97f2007-11-11 14:26:47 +00002492 target_sigset_t *set, CPUState *regs)
bellard106ec872006-06-27 21:08:10 +00002493{
2494 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002495 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002496 int i;
2497
bellard579a97f2007-11-11 14:26:47 +00002498 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2499 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002500 goto give_sigsegv;
2501
2502 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2503
2504 if(setup_sigcontext(regs, &frame->sf_sc))
2505 goto give_sigsegv;
2506
2507 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2508 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2509 goto give_sigsegv;
2510 }
2511
2512 /*
2513 * Arguments to signal handler:
2514 *
2515 * a0 = signal number
2516 * a1 = 0 (should be cause)
2517 * a2 = pointer to struct sigcontext
2518 *
2519 * $25 and PC point to the signal handler, $29 points to the
2520 * struct sigframe.
2521 */
thsb5dc7732008-06-27 10:02:35 +00002522 regs->active_tc.gpr[ 4] = sig;
2523 regs->active_tc.gpr[ 5] = 0;
2524 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2525 regs->active_tc.gpr[29] = frame_addr;
2526 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002527 /* The original kernel code sets CP0_EPC to the handler
2528 * since it returns to userland using eret
2529 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002530 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
bellard579a97f2007-11-11 14:26:47 +00002531 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002532 return;
2533
2534give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002535 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002536 force_sig(TARGET_SIGSEGV/*, current*/);
ths5fafdf22007-09-16 21:08:06 +00002537 return;
bellard106ec872006-06-27 21:08:10 +00002538}
2539
2540long do_sigreturn(CPUState *regs)
2541{
ths388bb212007-05-13 13:58:00 +00002542 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002543 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002544 sigset_t blocked;
2545 target_sigset_t target_set;
2546 int i;
bellard106ec872006-06-27 21:08:10 +00002547
2548#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002549 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002550#endif
thsb5dc7732008-06-27 10:02:35 +00002551 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002552 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002553 goto badframe;
2554
ths388bb212007-05-13 13:58:00 +00002555 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002556 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2557 goto badframe;
ths388bb212007-05-13 13:58:00 +00002558 }
bellard106ec872006-06-27 21:08:10 +00002559
ths388bb212007-05-13 13:58:00 +00002560 target_to_host_sigset_internal(&blocked, &target_set);
2561 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002562
ths388bb212007-05-13 13:58:00 +00002563 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002564 goto badframe;
2565
2566#if 0
ths388bb212007-05-13 13:58:00 +00002567 /*
2568 * Don't let your children do this ...
2569 */
2570 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002571 "move\t$29, %0\n\t"
2572 "j\tsyscall_exit"
2573 :/* no outputs */
2574 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002575 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002576#endif
ths3b46e622007-09-17 08:09:54 +00002577
thsb5dc7732008-06-27 10:02:35 +00002578 regs->active_tc.PC = regs->CP0_EPC;
ths388bb212007-05-13 13:58:00 +00002579 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002580 * maybe a problem with nested signals ? */
2581 regs->CP0_EPC = 0;
2582 return 0;
2583
2584badframe:
ths388bb212007-05-13 13:58:00 +00002585 force_sig(TARGET_SIGSEGV/*, current*/);
2586 return 0;
bellard106ec872006-06-27 21:08:10 +00002587}
2588
pbrook624f7972008-05-31 16:11:38 +00002589static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard106ec872006-06-27 21:08:10 +00002590 target_siginfo_t *info,
2591 target_sigset_t *set, CPUState *env)
2592{
2593 fprintf(stderr, "setup_rt_frame: not implemented\n");
2594}
2595
2596long do_rt_sigreturn(CPUState *env)
2597{
2598 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002599 return -TARGET_ENOSYS;
bellard106ec872006-06-27 21:08:10 +00002600}
bellard6d5e2162004-09-30 22:04:13 +00002601
thsc3b5bc82007-12-02 06:31:25 +00002602#elif defined(TARGET_SH4)
2603
2604/*
2605 * code and data structures from linux kernel:
2606 * include/asm-sh/sigcontext.h
2607 * arch/sh/kernel/signal.c
2608 */
2609
2610struct target_sigcontext {
2611 target_ulong oldmask;
2612
2613 /* CPU registers */
2614 target_ulong sc_gregs[16];
2615 target_ulong sc_pc;
2616 target_ulong sc_pr;
2617 target_ulong sc_sr;
2618 target_ulong sc_gbr;
2619 target_ulong sc_mach;
2620 target_ulong sc_macl;
2621
2622 /* FPU registers */
2623 target_ulong sc_fpregs[16];
2624 target_ulong sc_xfpregs[16];
2625 unsigned int sc_fpscr;
2626 unsigned int sc_fpul;
2627 unsigned int sc_ownedfp;
2628};
2629
2630struct target_sigframe
2631{
2632 struct target_sigcontext sc;
2633 target_ulong extramask[TARGET_NSIG_WORDS-1];
2634 uint16_t retcode[3];
2635};
2636
2637
2638struct target_ucontext {
2639 target_ulong uc_flags;
2640 struct target_ucontext *uc_link;
2641 target_stack_t uc_stack;
2642 struct target_sigcontext uc_mcontext;
2643 target_sigset_t uc_sigmask; /* mask last for extensibility */
2644};
2645
2646struct target_rt_sigframe
2647{
2648 struct target_siginfo info;
2649 struct target_ucontext uc;
2650 uint16_t retcode[3];
2651};
2652
2653
2654#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
2655#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
2656
pbrook624f7972008-05-31 16:11:38 +00002657static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002658 unsigned long sp, size_t frame_size)
2659{
pbrook624f7972008-05-31 16:11:38 +00002660 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00002661 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2662 }
2663
2664 return (sp - frame_size) & -8ul;
2665}
2666
2667static int setup_sigcontext(struct target_sigcontext *sc,
2668 CPUState *regs, unsigned long mask)
2669{
2670 int err = 0;
2671
2672#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
2673 COPY(gregs[0]); COPY(gregs[1]);
2674 COPY(gregs[2]); COPY(gregs[3]);
2675 COPY(gregs[4]); COPY(gregs[5]);
2676 COPY(gregs[6]); COPY(gregs[7]);
2677 COPY(gregs[8]); COPY(gregs[9]);
2678 COPY(gregs[10]); COPY(gregs[11]);
2679 COPY(gregs[12]); COPY(gregs[13]);
2680 COPY(gregs[14]); COPY(gregs[15]);
2681 COPY(gbr); COPY(mach);
2682 COPY(macl); COPY(pr);
2683 COPY(sr); COPY(pc);
2684#undef COPY
2685
2686 /* todo: save FPU registers here */
2687
2688 /* non-iBCS2 extensions.. */
2689 err |= __put_user(mask, &sc->oldmask);
2690
2691 return err;
2692}
2693
pbrookc2764712009-03-07 15:24:59 +00002694static int restore_sigcontext(CPUState *regs,
thsc3b5bc82007-12-02 06:31:25 +00002695 struct target_sigcontext *sc)
2696{
2697 unsigned int err = 0;
2698
2699#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
2700 COPY(gregs[1]);
2701 COPY(gregs[2]); COPY(gregs[3]);
2702 COPY(gregs[4]); COPY(gregs[5]);
2703 COPY(gregs[6]); COPY(gregs[7]);
2704 COPY(gregs[8]); COPY(gregs[9]);
2705 COPY(gregs[10]); COPY(gregs[11]);
2706 COPY(gregs[12]); COPY(gregs[13]);
2707 COPY(gregs[14]); COPY(gregs[15]);
2708 COPY(gbr); COPY(mach);
2709 COPY(macl); COPY(pr);
2710 COPY(sr); COPY(pc);
2711#undef COPY
2712
2713 /* todo: restore FPU registers here */
2714
2715 regs->tra = -1; /* disable syscall checks */
2716 return err;
2717}
2718
pbrook624f7972008-05-31 16:11:38 +00002719static void setup_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002720 target_sigset_t *set, CPUState *regs)
2721{
2722 struct target_sigframe *frame;
2723 abi_ulong frame_addr;
2724 int i;
2725 int err = 0;
2726 int signal;
2727
2728 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2729 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2730 goto give_sigsegv;
2731
2732 signal = current_exec_domain_sig(sig);
2733
2734 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
2735
2736 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2737 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
2738 }
2739
2740 /* Set up to return from userspace. If provided, use a stub
2741 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002742 if (ka->sa_flags & TARGET_SA_RESTORER) {
2743 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002744 } else {
2745 /* Generate return code (system call to sigreturn) */
2746 err |= __put_user(MOVW(2), &frame->retcode[0]);
2747 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2748 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
2749 regs->pr = (unsigned long) frame->retcode;
2750 }
2751
2752 if (err)
2753 goto give_sigsegv;
2754
2755 /* Set up registers for signal handler */
2756 regs->gregs[15] = (unsigned long) frame;
2757 regs->gregs[4] = signal; /* Arg for signal handler */
2758 regs->gregs[5] = 0;
2759 regs->gregs[6] = (unsigned long) &frame->sc;
pbrook624f7972008-05-31 16:11:38 +00002760 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002761
2762 unlock_user_struct(frame, frame_addr, 1);
2763 return;
2764
2765give_sigsegv:
2766 unlock_user_struct(frame, frame_addr, 1);
2767 force_sig(SIGSEGV);
2768}
2769
pbrook624f7972008-05-31 16:11:38 +00002770static void setup_rt_frame(int sig, struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002771 target_siginfo_t *info,
2772 target_sigset_t *set, CPUState *regs)
2773{
2774 struct target_rt_sigframe *frame;
2775 abi_ulong frame_addr;
2776 int i;
2777 int err = 0;
2778 int signal;
2779
2780 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2781 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2782 goto give_sigsegv;
2783
2784 signal = current_exec_domain_sig(sig);
2785
2786 err |= copy_siginfo_to_user(&frame->info, info);
2787
2788 /* Create the ucontext. */
2789 err |= __put_user(0, &frame->uc.uc_flags);
2790 err |= __put_user(0, (unsigned long *)&frame->uc.uc_link);
balrog526ccb72008-07-16 12:13:52 +00002791 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
thsc3b5bc82007-12-02 06:31:25 +00002792 &frame->uc.uc_stack.ss_sp);
2793 err |= __put_user(sas_ss_flags(regs->gregs[15]),
2794 &frame->uc.uc_stack.ss_flags);
2795 err |= __put_user(target_sigaltstack_used.ss_size,
2796 &frame->uc.uc_stack.ss_size);
2797 err |= setup_sigcontext(&frame->uc.uc_mcontext,
2798 regs, set->sig[0]);
2799 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2800 err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]);
2801 }
2802
2803 /* Set up to return from userspace. If provided, use a stub
2804 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00002805 if (ka->sa_flags & TARGET_SA_RESTORER) {
2806 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00002807 } else {
2808 /* Generate return code (system call to sigreturn) */
2809 err |= __put_user(MOVW(2), &frame->retcode[0]);
2810 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
2811 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
2812 regs->pr = (unsigned long) frame->retcode;
2813 }
2814
2815 if (err)
2816 goto give_sigsegv;
2817
2818 /* Set up registers for signal handler */
2819 regs->gregs[15] = (unsigned long) frame;
2820 regs->gregs[4] = signal; /* Arg for signal handler */
2821 regs->gregs[5] = (unsigned long) &frame->info;
2822 regs->gregs[6] = (unsigned long) &frame->uc;
pbrook624f7972008-05-31 16:11:38 +00002823 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00002824
2825 unlock_user_struct(frame, frame_addr, 1);
2826 return;
2827
2828give_sigsegv:
2829 unlock_user_struct(frame, frame_addr, 1);
2830 force_sig(SIGSEGV);
2831}
2832
2833long do_sigreturn(CPUState *regs)
2834{
2835 struct target_sigframe *frame;
2836 abi_ulong frame_addr;
2837 sigset_t blocked;
2838 target_sigset_t target_set;
2839 int i;
2840 int err = 0;
2841
2842#if defined(DEBUG_SIGNAL)
2843 fprintf(stderr, "do_sigreturn\n");
2844#endif
2845 frame_addr = regs->gregs[15];
2846 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2847 goto badframe;
2848
2849 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
2850 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2851 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
2852 }
2853
2854 if (err)
2855 goto badframe;
2856
2857 target_to_host_sigset_internal(&blocked, &target_set);
2858 sigprocmask(SIG_SETMASK, &blocked, NULL);
2859
2860 if (restore_sigcontext(regs, &frame->sc))
2861 goto badframe;
2862
2863 unlock_user_struct(frame, frame_addr, 0);
2864 return regs->gregs[0];
2865
2866badframe:
2867 unlock_user_struct(frame, frame_addr, 0);
2868 force_sig(TARGET_SIGSEGV);
2869 return 0;
2870}
2871
2872long do_rt_sigreturn(CPUState *regs)
2873{
2874 struct target_rt_sigframe *frame;
2875 abi_ulong frame_addr;
2876 sigset_t blocked;
2877
2878#if defined(DEBUG_SIGNAL)
2879 fprintf(stderr, "do_rt_sigreturn\n");
2880#endif
2881 frame_addr = regs->gregs[15];
2882 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2883 goto badframe;
2884
2885 target_to_host_sigset(&blocked, &frame->uc.uc_sigmask);
2886 sigprocmask(SIG_SETMASK, &blocked, NULL);
2887
2888 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
2889 goto badframe;
2890
2891 if (do_sigaltstack(frame_addr +
2892 offsetof(struct target_rt_sigframe, uc.uc_stack),
2893 0, get_sp_from_cpustate(regs)) == -EFAULT)
2894 goto badframe;
2895
2896 unlock_user_struct(frame, frame_addr, 0);
2897 return regs->gregs[0];
2898
2899badframe:
2900 unlock_user_struct(frame, frame_addr, 0);
2901 force_sig(TARGET_SIGSEGV);
2902 return 0;
2903}
edgar_iglb6d3abd2008-02-28 11:29:27 +00002904#elif defined(TARGET_CRIS)
2905
2906struct target_sigcontext {
2907 struct target_pt_regs regs; /* needs to be first */
2908 uint32_t oldmask;
2909 uint32_t usp; /* usp before stacking this gunk on it */
2910};
2911
2912/* Signal frames. */
2913struct target_signal_frame {
2914 struct target_sigcontext sc;
2915 uint32_t extramask[TARGET_NSIG_WORDS - 1];
2916 uint8_t retcode[8]; /* Trampoline code. */
2917};
2918
2919struct rt_signal_frame {
2920 struct siginfo *pinfo;
2921 void *puc;
2922 struct siginfo info;
2923 struct ucontext uc;
2924 uint8_t retcode[8]; /* Trampoline code. */
2925};
2926
2927static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
2928{
edgar_igl9664d922008-03-03 22:23:53 +00002929 __put_user(env->regs[0], &sc->regs.r0);
2930 __put_user(env->regs[1], &sc->regs.r1);
2931 __put_user(env->regs[2], &sc->regs.r2);
2932 __put_user(env->regs[3], &sc->regs.r3);
2933 __put_user(env->regs[4], &sc->regs.r4);
2934 __put_user(env->regs[5], &sc->regs.r5);
2935 __put_user(env->regs[6], &sc->regs.r6);
2936 __put_user(env->regs[7], &sc->regs.r7);
2937 __put_user(env->regs[8], &sc->regs.r8);
2938 __put_user(env->regs[9], &sc->regs.r9);
2939 __put_user(env->regs[10], &sc->regs.r10);
2940 __put_user(env->regs[11], &sc->regs.r11);
2941 __put_user(env->regs[12], &sc->regs.r12);
2942 __put_user(env->regs[13], &sc->regs.r13);
2943 __put_user(env->regs[14], &sc->usp);
2944 __put_user(env->regs[15], &sc->regs.acr);
2945 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
2946 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
2947 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002948}
edgar_igl9664d922008-03-03 22:23:53 +00002949
edgar_iglb6d3abd2008-02-28 11:29:27 +00002950static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
2951{
edgar_igl9664d922008-03-03 22:23:53 +00002952 __get_user(env->regs[0], &sc->regs.r0);
2953 __get_user(env->regs[1], &sc->regs.r1);
2954 __get_user(env->regs[2], &sc->regs.r2);
2955 __get_user(env->regs[3], &sc->regs.r3);
2956 __get_user(env->regs[4], &sc->regs.r4);
2957 __get_user(env->regs[5], &sc->regs.r5);
2958 __get_user(env->regs[6], &sc->regs.r6);
2959 __get_user(env->regs[7], &sc->regs.r7);
2960 __get_user(env->regs[8], &sc->regs.r8);
2961 __get_user(env->regs[9], &sc->regs.r9);
2962 __get_user(env->regs[10], &sc->regs.r10);
2963 __get_user(env->regs[11], &sc->regs.r11);
2964 __get_user(env->regs[12], &sc->regs.r12);
2965 __get_user(env->regs[13], &sc->regs.r13);
2966 __get_user(env->regs[14], &sc->usp);
2967 __get_user(env->regs[15], &sc->regs.acr);
2968 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
2969 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
2970 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00002971}
2972
edgar_igl9664d922008-03-03 22:23:53 +00002973static abi_ulong get_sigframe(CPUState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00002974{
edgar_igl9664d922008-03-03 22:23:53 +00002975 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002976 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00002977 sp = (env->regs[R_SP] & ~3);
2978 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002979}
2980
pbrook624f7972008-05-31 16:11:38 +00002981static void setup_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00002982 target_sigset_t *set, CPUState *env)
2983{
2984 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00002985 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002986 int err = 0;
2987 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00002988
edgar_igl9664d922008-03-03 22:23:53 +00002989 frame_addr = get_sigframe(env, sizeof *frame);
2990 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00002991 goto badframe;
2992
2993 /*
2994 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
2995 * use this trampoline anymore but it sets it up for GDB.
2996 * In QEMU, using the trampoline simplifies things a bit so we use it.
2997 *
2998 * This is movu.w __NR_sigreturn, r9; break 13;
2999 */
3000 err |= __put_user(0x9c5f, frame->retcode+0);
3001 err |= __put_user(TARGET_NR_sigreturn,
3002 frame->retcode+2);
3003 err |= __put_user(0xe93d, frame->retcode+4);
3004
3005 /* Save the mask. */
3006 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3007 if (err)
3008 goto badframe;
3009
3010 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3011 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3012 goto badframe;
3013 }
3014
3015 setup_sigcontext(&frame->sc, env);
3016
3017 /* Move the stack and setup the arguments for the handler. */
balrog526ccb72008-07-16 12:13:52 +00003018 env->regs[R_SP] = (uint32_t) (unsigned long) frame;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003019 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003020 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003021 /* Link SRP so the guest returns through the trampoline. */
balrog526ccb72008-07-16 12:13:52 +00003022 env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003023
edgar_igl9664d922008-03-03 22:23:53 +00003024 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003025 return;
3026 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003027 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003028 force_sig(TARGET_SIGSEGV);
3029}
3030
pbrook624f7972008-05-31 16:11:38 +00003031static void setup_rt_frame(int sig, struct target_sigaction *ka,
edgar_iglb6d3abd2008-02-28 11:29:27 +00003032 target_siginfo_t *info,
3033 target_sigset_t *set, CPUState *env)
3034{
3035 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3036}
3037
3038long do_sigreturn(CPUState *env)
3039{
3040 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003041 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003042 target_sigset_t target_set;
3043 sigset_t set;
3044 int i;
3045
edgar_igl9664d922008-03-03 22:23:53 +00003046 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003047 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003048 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003049 goto badframe;
3050
3051 /* Restore blocked signals */
3052 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3053 goto badframe;
3054 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3055 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3056 goto badframe;
3057 }
3058 target_to_host_sigset_internal(&set, &target_set);
3059 sigprocmask(SIG_SETMASK, &set, NULL);
3060
3061 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003062 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003063 return env->regs[10];
3064 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003065 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003066 force_sig(TARGET_SIGSEGV);
3067}
3068
3069long do_rt_sigreturn(CPUState *env)
3070{
3071 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3072 return -TARGET_ENOSYS;
3073}
thsc3b5bc82007-12-02 06:31:25 +00003074
bellardb346ff42003-06-15 20:05:50 +00003075#else
3076
pbrook624f7972008-05-31 16:11:38 +00003077static void setup_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003078 target_sigset_t *set, CPUState *env)
3079{
3080 fprintf(stderr, "setup_frame: not implemented\n");
3081}
3082
pbrook624f7972008-05-31 16:11:38 +00003083static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellardb346ff42003-06-15 20:05:50 +00003084 target_siginfo_t *info,
3085 target_sigset_t *set, CPUState *env)
3086{
3087 fprintf(stderr, "setup_rt_frame: not implemented\n");
3088}
3089
3090long do_sigreturn(CPUState *env)
3091{
3092 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003093 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003094}
3095
3096long do_rt_sigreturn(CPUState *env)
3097{
3098 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00003099 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00003100}
3101
bellard66fb9762003-03-23 01:06:05 +00003102#endif
3103
pbrook624f7972008-05-31 16:11:38 +00003104void process_pending_signals(CPUState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00003105{
3106 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00003107 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00003108 sigset_t set, old_set;
3109 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00003110 struct emulated_sigtable *k;
3111 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00003112 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00003113 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00003114
pbrook624f7972008-05-31 16:11:38 +00003115 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00003116 return;
3117
pbrook624f7972008-05-31 16:11:38 +00003118 /* FIXME: This is not threadsafe. */
3119 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00003120 for(sig = 1; sig <= TARGET_NSIG; sig++) {
3121 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00003122 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00003123 k++;
bellard31e31b82003-02-18 22:55:36 +00003124 }
3125 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00003126 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00003127 return;
bellard66fb9762003-03-23 01:06:05 +00003128
bellard31e31b82003-02-18 22:55:36 +00003129 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00003130#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00003131 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00003132#endif
3133 /* dequeue signal */
3134 q = k->first;
3135 k->first = q->next;
3136 if (!k->first)
3137 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00003138
bellard1fddef42005-04-17 19:16:13 +00003139 sig = gdb_handlesig (cpu_env, sig);
3140 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00003141 sa = NULL;
3142 handler = TARGET_SIG_IGN;
3143 } else {
3144 sa = &sigact_table[sig - 1];
3145 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00003146 }
bellard66fb9762003-03-23 01:06:05 +00003147
bellard66fb9762003-03-23 01:06:05 +00003148 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00003149 /* default handler : ignore some signal. The other are job control or fatal */
3150 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
3151 kill(getpid(),SIGSTOP);
3152 } else if (sig != TARGET_SIGCHLD &&
3153 sig != TARGET_SIGURG &&
3154 sig != TARGET_SIGWINCH &&
3155 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00003156 force_sig(sig);
3157 }
3158 } else if (handler == TARGET_SIG_IGN) {
3159 /* ignore sig */
3160 } else if (handler == TARGET_SIG_ERR) {
3161 force_sig(sig);
3162 } else {
bellard9de5e442003-03-23 16:49:39 +00003163 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00003164 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00003165 /* SA_NODEFER indicates that the current signal should not be
3166 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00003167 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00003168 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00003169
bellard9de5e442003-03-23 16:49:39 +00003170 /* block signals in the handler using Linux */
3171 sigprocmask(SIG_BLOCK, &set, &old_set);
3172 /* save the previous blocked signal state to restore it at the
3173 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00003174 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00003175
bellardbc8a22c2003-03-30 21:02:40 +00003176 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00003177#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00003178 {
3179 CPUX86State *env = cpu_env;
3180 if (env->eflags & VM_MASK)
3181 save_v86_state(env);
3182 }
3183#endif
bellard9de5e442003-03-23 16:49:39 +00003184 /* prepare the stack frame of the virtual CPU */
pbrook624f7972008-05-31 16:11:38 +00003185 if (sa->sa_flags & TARGET_SA_SIGINFO)
3186 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00003187 else
pbrook624f7972008-05-31 16:11:38 +00003188 setup_frame(sig, sa, &target_old_set, cpu_env);
3189 if (sa->sa_flags & TARGET_SA_RESETHAND)
3190 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00003191 }
bellard66fb9762003-03-23 01:06:05 +00003192 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00003193 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00003194}