blob: 7da676f64ca09fcb102238f11d51b8bd859bab07 [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
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
19#include <stdlib.h>
20#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000021#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000022#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000023#include <unistd.h>
bellard66fb9762003-03-23 01:06:05 +000024#include <errno.h>
aurel32603e4fd2009-04-15 16:18:38 +000025#include <assert.h>
bellard31e31b82003-02-18 22:55:36 +000026#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030027#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000028
bellard3ef693a2003-03-23 20:17:16 +000029#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000030#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000031#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000032
33//#define DEBUG_SIGNAL
34
blueswir1249c4c32008-10-05 11:09:37 +000035static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000036 .ss_sp = 0,
37 .ss_size = 0,
38 .ss_flags = TARGET_SS_DISABLE,
39};
40
pbrook624f7972008-05-31 16:11:38 +000041static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000042
ths5fafdf22007-09-16 21:08:06 +000043static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000044 void *puc);
45
Arnaud Patard3ca05582009-03-30 01:18:20 +020046static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGHUP] = TARGET_SIGHUP,
48 [SIGINT] = TARGET_SIGINT,
49 [SIGQUIT] = TARGET_SIGQUIT,
50 [SIGILL] = TARGET_SIGILL,
51 [SIGTRAP] = TARGET_SIGTRAP,
52 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000053/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000054 [SIGBUS] = TARGET_SIGBUS,
55 [SIGFPE] = TARGET_SIGFPE,
56 [SIGKILL] = TARGET_SIGKILL,
57 [SIGUSR1] = TARGET_SIGUSR1,
58 [SIGSEGV] = TARGET_SIGSEGV,
59 [SIGUSR2] = TARGET_SIGUSR2,
60 [SIGPIPE] = TARGET_SIGPIPE,
61 [SIGALRM] = TARGET_SIGALRM,
62 [SIGTERM] = TARGET_SIGTERM,
63#ifdef SIGSTKFLT
64 [SIGSTKFLT] = TARGET_SIGSTKFLT,
65#endif
66 [SIGCHLD] = TARGET_SIGCHLD,
67 [SIGCONT] = TARGET_SIGCONT,
68 [SIGSTOP] = TARGET_SIGSTOP,
69 [SIGTSTP] = TARGET_SIGTSTP,
70 [SIGTTIN] = TARGET_SIGTTIN,
71 [SIGTTOU] = TARGET_SIGTTOU,
72 [SIGURG] = TARGET_SIGURG,
73 [SIGXCPU] = TARGET_SIGXCPU,
74 [SIGXFSZ] = TARGET_SIGXFSZ,
75 [SIGVTALRM] = TARGET_SIGVTALRM,
76 [SIGPROF] = TARGET_SIGPROF,
77 [SIGWINCH] = TARGET_SIGWINCH,
78 [SIGIO] = TARGET_SIGIO,
79 [SIGPWR] = TARGET_SIGPWR,
80 [SIGSYS] = TARGET_SIGSYS,
81 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000082 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080083 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000084 To fix this properly we need to do manual signal delivery multiplexed
85 over a single host signal. */
86 [__SIGRTMIN] = __SIGRTMAX,
87 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000088};
Arnaud Patard3ca05582009-03-30 01:18:20 +020089static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000090
thsa04e1342007-09-27 13:57:58 +000091static inline int on_sig_stack(unsigned long sp)
92{
93 return (sp - target_sigaltstack_used.ss_sp
94 < target_sigaltstack_used.ss_size);
95}
96
97static inline int sas_ss_flags(unsigned long sp)
98{
99 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
100 : on_sig_stack(sp) ? SS_ONSTACK : 0);
101}
102
pbrook1d9d8b52009-04-16 15:17:02 +0000103int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000104{
Arnaud Patard3ca05582009-03-30 01:18:20 +0200105 if (sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000106 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000107 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
pbrook4cb05962008-05-30 18:05:19 +0000110int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000111{
Arnaud Patard3ca05582009-03-30 01:18:20 +0200112 if (sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000113 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000114 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000115}
116
Anthony Liguoric227f092009-10-01 16:12:16 -0500117static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000118{
119 memset(set, 0, sizeof(*set));
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000123{
124 signum--;
125 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
126 set->sig[signum / TARGET_NSIG_BPW] |= mask;
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000130{
131 signum--;
132 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
133 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
134}
135
Anthony Liguoric227f092009-10-01 16:12:16 -0500136static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000137 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000138{
139 int i;
pbrookf5545b52008-05-30 22:37:07 +0000140 target_sigemptyset(d);
141 for (i = 1; i <= TARGET_NSIG; i++) {
142 if (sigismember(s, i)) {
143 target_sigaddset(d, host_to_target_signal(i));
144 }
bellard9e5f5282003-07-13 17:33:54 +0000145 }
bellard66fb9762003-03-23 01:06:05 +0000146}
147
Anthony Liguoric227f092009-10-01 16:12:16 -0500148void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000149{
Anthony Liguoric227f092009-10-01 16:12:16 -0500150 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000151 int i;
152
153 host_to_target_sigset_internal(&d1, s);
154 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200155 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000156}
157
blueswir18fcd3692008-08-17 20:26:25 +0000158static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500159 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000160{
161 int i;
pbrookf5545b52008-05-30 22:37:07 +0000162 sigemptyset(d);
163 for (i = 1; i <= TARGET_NSIG; i++) {
164 if (target_sigismember(s, i)) {
165 sigaddset(d, target_to_host_signal(i));
166 }
167 }
bellard66fb9762003-03-23 01:06:05 +0000168}
169
Anthony Liguoric227f092009-10-01 16:12:16 -0500170void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000171{
Anthony Liguoric227f092009-10-01 16:12:16 -0500172 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000173 int i;
174
175 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200176 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000177 target_to_host_sigset_internal(d, &s1);
178}
ths3b46e622007-09-17 08:09:54 +0000179
blueswir1992f48a2007-10-14 16:27:31 +0000180void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000181 const sigset_t *sigset)
182{
Anthony Liguoric227f092009-10-01 16:12:16 -0500183 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000184 host_to_target_sigset(&d, sigset);
185 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000186}
187
ths5fafdf22007-09-16 21:08:06 +0000188void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000189 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000190{
Anthony Liguoric227f092009-10-01 16:12:16 -0500191 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000192 int i;
193
194 d.sig[0] = *old_sigset;
195 for(i = 1;i < TARGET_NSIG_WORDS; i++)
196 d.sig[i] = 0;
197 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000198}
199
bellard9de5e442003-03-23 16:49:39 +0000200/* siginfo conversion */
201
Anthony Liguoric227f092009-10-01 16:12:16 -0500202static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000203 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000204{
Richard Hendersona05c6402012-09-15 11:34:20 -0700205 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000206 tinfo->si_signo = sig;
207 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000208 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700209
210 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
211 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
212 /* Should never come here, but who knows. The information for
213 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000214 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700215 } else if (sig == TARGET_SIGIO) {
216 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000217 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700218 } else if (sig == TARGET_SIGCHLD) {
219 tinfo->_sifields._sigchld._pid = info->si_pid;
220 tinfo->_sifields._sigchld._uid = info->si_uid;
221 tinfo->_sifields._sigchld._status
222 = host_to_target_waitstatus(info->si_status);
223 tinfo->_sifields._sigchld._utime = info->si_utime;
224 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000225 } else if (sig >= TARGET_SIGRTMIN) {
226 tinfo->_sifields._rt._pid = info->si_pid;
227 tinfo->_sifields._rt._uid = info->si_uid;
228 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700229 tinfo->_sifields._rt._sigval.sival_ptr
230 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000231 }
bellard66fb9762003-03-23 01:06:05 +0000232}
233
Anthony Liguoric227f092009-10-01 16:12:16 -0500234static void tswap_siginfo(target_siginfo_t *tinfo,
235 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000236{
Richard Hendersona05c6402012-09-15 11:34:20 -0700237 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000238 tinfo->si_signo = tswap32(sig);
239 tinfo->si_errno = tswap32(info->si_errno);
240 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700241
242 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
243 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
244 tinfo->_sifields._sigfault._addr
245 = tswapal(info->_sifields._sigfault._addr);
246 } else if (sig == TARGET_SIGIO) {
247 tinfo->_sifields._sigpoll._band
248 = tswap32(info->_sifields._sigpoll._band);
249 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
250 } else if (sig == TARGET_SIGCHLD) {
251 tinfo->_sifields._sigchld._pid
252 = tswap32(info->_sifields._sigchld._pid);
253 tinfo->_sifields._sigchld._uid
254 = tswap32(info->_sifields._sigchld._uid);
255 tinfo->_sifields._sigchld._status
256 = tswap32(info->_sifields._sigchld._status);
257 tinfo->_sifields._sigchld._utime
258 = tswapal(info->_sifields._sigchld._utime);
259 tinfo->_sifields._sigchld._stime
260 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000261 } else if (sig >= TARGET_SIGRTMIN) {
262 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
263 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700264 tinfo->_sifields._rt._sigval.sival_ptr
265 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000266 }
267}
268
269
Anthony Liguoric227f092009-10-01 16:12:16 -0500270void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000271{
272 host_to_target_siginfo_noswap(tinfo, info);
273 tswap_siginfo(tinfo, tinfo);
274}
275
276/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000277/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500278void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000279{
280 info->si_signo = tswap32(tinfo->si_signo);
281 info->si_errno = tswap32(tinfo->si_errno);
282 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000283 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
284 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000285 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200286 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000287}
288
aurel32ca587a82008-12-18 22:44:13 +0000289static int fatal_signal (int sig)
290{
291 switch (sig) {
292 case TARGET_SIGCHLD:
293 case TARGET_SIGURG:
294 case TARGET_SIGWINCH:
295 /* Ignored by default. */
296 return 0;
297 case TARGET_SIGCONT:
298 case TARGET_SIGSTOP:
299 case TARGET_SIGTSTP:
300 case TARGET_SIGTTIN:
301 case TARGET_SIGTTOU:
302 /* Job control signals. */
303 return 0;
304 default:
305 return 1;
306 }
307}
308
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300309/* returns 1 if given signal should dump core if not handled */
310static int core_dump_signal(int sig)
311{
312 switch (sig) {
313 case TARGET_SIGABRT:
314 case TARGET_SIGFPE:
315 case TARGET_SIGILL:
316 case TARGET_SIGQUIT:
317 case TARGET_SIGSEGV:
318 case TARGET_SIGTRAP:
319 case TARGET_SIGBUS:
320 return (1);
321 default:
322 return (0);
323 }
324}
325
bellard31e31b82003-02-18 22:55:36 +0000326void signal_init(void)
327{
328 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000329 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000330 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000331 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000332
bellard9e5f5282003-07-13 17:33:54 +0000333 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200334 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000335 if (host_to_target_signal_table[i] == 0)
336 host_to_target_signal_table[i] = i;
337 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200338 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000339 j = host_to_target_signal_table[i];
340 target_to_host_signal_table[j] = i;
341 }
ths3b46e622007-09-17 08:09:54 +0000342
bellard9de5e442003-03-23 16:49:39 +0000343 /* set all host signal handlers. ALL signals are blocked during
344 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000345 memset(sigact_table, 0, sizeof(sigact_table));
346
bellard9de5e442003-03-23 16:49:39 +0000347 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000348 act.sa_flags = SA_SIGINFO;
349 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000350 for(i = 1; i <= TARGET_NSIG; i++) {
351 host_sig = target_to_host_signal(i);
352 sigaction(host_sig, NULL, &oact);
353 if (oact.sa_sigaction == (void *)SIG_IGN) {
354 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
355 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
356 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
357 }
358 /* If there's already a handler installed then something has
359 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000360 /* Install some handlers for our own use. We need at least
361 SIGSEGV and SIGBUS, to detect exceptions. We can not just
362 trap all signals because it affects syscall interrupt
363 behavior. But do trap all default-fatal signals. */
364 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000365 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000366 }
bellard31e31b82003-02-18 22:55:36 +0000367}
368
bellard66fb9762003-03-23 01:06:05 +0000369/* signal queue handling */
370
Andreas Färber9349b4f2012-03-14 01:38:32 +0100371static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000372{
pbrook624f7972008-05-31 16:11:38 +0000373 TaskState *ts = env->opaque;
374 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000375 if (!q)
376 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000377 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000378 return q;
379}
380
Andreas Färber9349b4f2012-03-14 01:38:32 +0100381static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000382{
pbrook624f7972008-05-31 16:11:38 +0000383 TaskState *ts = env->opaque;
384 q->next = ts->first_free;
385 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000386}
387
bellard9de5e442003-03-23 16:49:39 +0000388/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200389static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000390{
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300391 TaskState *ts = (TaskState *)thread_env->opaque;
392 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000393 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200394 host_sig = target_to_host_signal(target_sig);
395 gdb_signalled(thread_env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000396
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300397 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200398 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300399 stop_all_tasks();
400 core_dumped =
Riku Voipio66393fb2009-12-04 15:16:32 +0200401 ((*ts->bprm->core_dump)(target_sig, thread_env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300402 }
403 if (core_dumped) {
404 /* we already dumped the core of target process, we don't want
405 * a coredump of qemu itself */
406 struct rlimit nodump;
407 getrlimit(RLIMIT_CORE, &nodump);
408 nodump.rlim_cur=0;
409 setrlimit(RLIMIT_CORE, &nodump);
410 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200411 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300412 }
413
Stefan Weil0c587512011-04-28 17:20:32 +0200414 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000415 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
416 * a negative value. To get the proper exit code we need to
417 * actually die from an uncaught signal. Here the default signal
418 * handler is installed, we send ourself a signal and we wait for
419 * it to arrive. */
420 sigfillset(&act.sa_mask);
421 act.sa_handler = SIG_DFL;
422 sigaction(host_sig, &act, NULL);
423
424 /* For some reason raise(host_sig) doesn't send the signal when
425 * statically linked on x86-64. */
426 kill(getpid(), host_sig);
427
428 /* Make sure the signal isn't masked (just reuse the mask inside
429 of act) */
430 sigdelset(&act.sa_mask, host_sig);
431 sigsuspend(&act.sa_mask);
432
433 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000434 abort();
bellard66fb9762003-03-23 01:06:05 +0000435}
436
bellard9de5e442003-03-23 16:49:39 +0000437/* queue a signal so that it will be send to the virtual CPU as soon
438 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100439int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000440{
pbrook624f7972008-05-31 16:11:38 +0000441 TaskState *ts = env->opaque;
442 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000443 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000444 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000445 int queue;
bellard66fb9762003-03-23 01:06:05 +0000446
bellard9de5e442003-03-23 16:49:39 +0000447#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000448 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000449 sig);
bellard66fb9762003-03-23 01:06:05 +0000450#endif
pbrook624f7972008-05-31 16:11:38 +0000451 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000452 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000453 handler = sigact_table[sig - 1]._sa_handler;
aurel32ca587a82008-12-18 22:44:13 +0000454 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000455 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
456 kill(getpid(),SIGSTOP);
457 return 0;
458 } else
bellard66fb9762003-03-23 01:06:05 +0000459 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000460 if (sig != TARGET_SIGCHLD &&
461 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000462 sig != TARGET_SIGWINCH &&
463 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000464 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000465 } else {
466 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000467 }
aurel32ca587a82008-12-18 22:44:13 +0000468 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000469 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000470 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000471 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000472 force_sig(sig);
473 } else {
bellard9de5e442003-03-23 16:49:39 +0000474 pq = &k->first;
475 if (sig < TARGET_SIGRTMIN) {
476 /* if non real time signal, we queue exactly one signal */
477 if (!k->pending)
478 q = &k->info;
479 else
480 return 0;
481 } else {
482 if (!k->pending) {
483 /* first signal */
484 q = &k->info;
485 } else {
pbrook624f7972008-05-31 16:11:38 +0000486 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000487 if (!q)
488 return -EAGAIN;
489 while (*pq != NULL)
490 pq = &(*pq)->next;
491 }
492 }
493 *pq = q;
494 q->info = *info;
495 q->next = NULL;
496 k->pending = 1;
497 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000498 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000499 return 1; /* indicates that the signal was queued */
500 }
501}
502
ths5fafdf22007-09-16 21:08:06 +0000503static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000504 void *puc)
505{
506 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500507 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000508
509 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000510 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000511 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000512 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000513 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000514 return;
515 }
516
517 /* get target signal number */
518 sig = host_to_target_signal(host_signum);
519 if (sig < 1 || sig > TARGET_NSIG)
520 return;
521#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000522 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000523#endif
524 host_to_target_siginfo_noswap(&tinfo, info);
pbrookd5975362008-06-07 20:50:51 +0000525 if (queue_signal(thread_env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000526 /* interrupt the virtual CPU as soon as possible */
aurel323098dba2009-03-07 21:28:24 +0000527 cpu_exit(thread_env);
bellard66fb9762003-03-23 01:06:05 +0000528 }
bellard31e31b82003-02-18 22:55:36 +0000529}
530
ths0da46a62007-10-20 20:23:07 +0000531/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000532/* compare linux/kernel/signal.c:do_sigaltstack() */
533abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000534{
535 int ret;
536 struct target_sigaltstack oss;
537
538 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000539 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000540 {
541 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
542 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
543 __put_user(sas_ss_flags(sp), &oss.ss_flags);
544 }
545
bellard579a97f2007-11-11 14:26:47 +0000546 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000547 {
bellard579a97f2007-11-11 14:26:47 +0000548 struct target_sigaltstack *uss;
549 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000550
ths0da46a62007-10-20 20:23:07 +0000551 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000552 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000553 || __get_user(ss.ss_sp, &uss->ss_sp)
554 || __get_user(ss.ss_size, &uss->ss_size)
555 || __get_user(ss.ss_flags, &uss->ss_flags))
556 goto out;
bellard579a97f2007-11-11 14:26:47 +0000557 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000558
ths0da46a62007-10-20 20:23:07 +0000559 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000560 if (on_sig_stack(sp))
561 goto out;
562
ths0da46a62007-10-20 20:23:07 +0000563 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000564 if (ss.ss_flags != TARGET_SS_DISABLE
565 && ss.ss_flags != TARGET_SS_ONSTACK
566 && ss.ss_flags != 0)
567 goto out;
568
569 if (ss.ss_flags == TARGET_SS_DISABLE) {
570 ss.ss_size = 0;
571 ss.ss_sp = 0;
572 } else {
ths0da46a62007-10-20 20:23:07 +0000573 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000574 if (ss.ss_size < MINSIGSTKSZ)
575 goto out;
576 }
577
578 target_sigaltstack_used.ss_sp = ss.ss_sp;
579 target_sigaltstack_used.ss_size = ss.ss_size;
580 }
581
bellard579a97f2007-11-11 14:26:47 +0000582 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000583 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000584 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000585 goto out;
thsa04e1342007-09-27 13:57:58 +0000586 }
587
588 ret = 0;
589out:
590 return ret;
591}
592
ths0da46a62007-10-20 20:23:07 +0000593/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000594int do_sigaction(int sig, const struct target_sigaction *act,
595 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000596{
pbrook624f7972008-05-31 16:11:38 +0000597 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000598 struct sigaction act1;
599 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000600 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000601
ths2a913eb2008-11-27 15:46:25 +0000602 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000603 return -EINVAL;
604 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000605#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000606 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
607 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000608#endif
609 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800610 __put_user(k->_sa_handler, &oact->_sa_handler);
611 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000612#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800613 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000614#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800615 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000616 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000617 }
618 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000619 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800620 __get_user(k->_sa_handler, &act->_sa_handler);
621 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000622#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800623 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000624#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800625 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000626 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000627
628 /* we update the host linux signal state */
629 host_sig = target_to_host_signal(sig);
630 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
631 sigfillset(&act1.sa_mask);
632 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000633 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000634 act1.sa_flags |= SA_RESTART;
635 /* NOTE: it is important to update the host kernel signal
636 ignore state to avoid getting unexpected interrupted
637 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000638 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000639 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000640 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000641 if (fatal_signal (sig))
642 act1.sa_sigaction = host_signal_handler;
643 else
644 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000645 } else {
646 act1.sa_sigaction = host_signal_handler;
647 }
ths0da46a62007-10-20 20:23:07 +0000648 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000649 }
bellard66fb9762003-03-23 01:06:05 +0000650 }
ths0da46a62007-10-20 20:23:07 +0000651 return ret;
bellard66fb9762003-03-23 01:06:05 +0000652}
bellard31e31b82003-02-18 22:55:36 +0000653
Anthony Liguoric227f092009-10-01 16:12:16 -0500654static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
655 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000656{
657 tswap_siginfo(tinfo, info);
658 return 0;
659}
660
thsc3b5bc82007-12-02 06:31:25 +0000661static inline int current_exec_domain_sig(int sig)
662{
663 return /* current->exec_domain && current->exec_domain->signal_invmap
664 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
665}
666
bellard459a4012007-11-11 19:45:10 +0000667#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000668
669/* from the Linux kernel */
670
671struct target_fpreg {
672 uint16_t significand[4];
673 uint16_t exponent;
674};
675
676struct target_fpxreg {
677 uint16_t significand[4];
678 uint16_t exponent;
679 uint16_t padding[3];
680};
681
682struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000683 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000684};
685
686struct target_fpstate {
687 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000688 abi_ulong cw;
689 abi_ulong sw;
690 abi_ulong tag;
691 abi_ulong ipoff;
692 abi_ulong cssel;
693 abi_ulong dataoff;
694 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000695 struct target_fpreg _st[8];
696 uint16_t status;
697 uint16_t magic; /* 0xffff = regular FPU data only */
698
699 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000700 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
701 abi_ulong mxcsr;
702 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000703 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
704 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000705 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000706};
707
708#define X86_FXSR_MAGIC 0x0000
709
710struct target_sigcontext {
711 uint16_t gs, __gsh;
712 uint16_t fs, __fsh;
713 uint16_t es, __esh;
714 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000715 abi_ulong edi;
716 abi_ulong esi;
717 abi_ulong ebp;
718 abi_ulong esp;
719 abi_ulong ebx;
720 abi_ulong edx;
721 abi_ulong ecx;
722 abi_ulong eax;
723 abi_ulong trapno;
724 abi_ulong err;
725 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000726 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000727 abi_ulong eflags;
728 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000729 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000730 abi_ulong fpstate; /* pointer */
731 abi_ulong oldmask;
732 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000733};
734
bellard66fb9762003-03-23 01:06:05 +0000735struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000736 abi_ulong tuc_flags;
737 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500738 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000739 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500740 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000741};
742
743struct sigframe
744{
blueswir1992f48a2007-10-14 16:27:31 +0000745 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000746 int sig;
747 struct target_sigcontext sc;
748 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000749 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000750 char retcode[8];
751};
752
753struct rt_sigframe
754{
blueswir1992f48a2007-10-14 16:27:31 +0000755 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000756 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000757 abi_ulong pinfo;
758 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000759 struct target_siginfo info;
760 struct target_ucontext uc;
761 struct target_fpstate fpstate;
762 char retcode[8];
763};
764
765/*
766 * Set up a signal frame.
767 */
768
bellard66fb9762003-03-23 01:06:05 +0000769/* XXX: save x87 state */
770static int
771setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000772 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000773{
774 int err = 0;
bellard775b58d2007-11-11 16:22:17 +0000775 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000776
bellard579a97f2007-11-11 14:26:47 +0000777 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000778 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
779 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
780 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
781 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000782 err |= __put_user(env->regs[R_EDI], &sc->edi);
783 err |= __put_user(env->regs[R_ESI], &sc->esi);
784 err |= __put_user(env->regs[R_EBP], &sc->ebp);
785 err |= __put_user(env->regs[R_ESP], &sc->esp);
786 err |= __put_user(env->regs[R_EBX], &sc->ebx);
787 err |= __put_user(env->regs[R_EDX], &sc->edx);
788 err |= __put_user(env->regs[R_ECX], &sc->ecx);
789 err |= __put_user(env->regs[R_EAX], &sc->eax);
bellard66099dd2003-05-08 15:34:02 +0000790 err |= __put_user(env->exception_index, &sc->trapno);
791 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000792 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000793 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000794 err |= __put_user(env->eflags, &sc->eflags);
795 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000796 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000797
bellard28be6232007-11-11 22:23:38 +0000798 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000799 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000800 magic = 0xffff;
801 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000802 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000803
bellard66fb9762003-03-23 01:06:05 +0000804 /* non-iBCS2 extensions.. */
805 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000806 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000807 return err;
808}
809
810/*
811 * Determine which stack to use..
812 */
813
bellard579a97f2007-11-11 14:26:47 +0000814static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000815get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000816{
817 unsigned long esp;
818
819 /* Default to using normal stack */
820 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000821 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000822 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000823 if (sas_ss_flags(esp) == 0)
824 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
825 }
bellard66fb9762003-03-23 01:06:05 +0000826
827 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000828 else
bellarda52c7572003-06-21 13:14:12 +0000829 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000830 !(ka->sa_flags & TARGET_SA_RESTORER) &&
831 ka->sa_restorer) {
832 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000833 }
bellard579a97f2007-11-11 14:26:47 +0000834 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000835}
836
bellard579a97f2007-11-11 14:26:47 +0000837/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000838static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500839 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000840{
bellard579a97f2007-11-11 14:26:47 +0000841 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000842 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000843 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000844
bellard579a97f2007-11-11 14:26:47 +0000845 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000846
bellard579a97f2007-11-11 14:26:47 +0000847 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000848 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000849
thsc3b5bc82007-12-02 06:31:25 +0000850 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000851 &frame->sig);
852 if (err)
853 goto give_sigsegv;
854
bellard28be6232007-11-11 22:23:38 +0000855 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
856 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000857 if (err)
858 goto give_sigsegv;
859
bellard92319442004-06-19 16:58:13 +0000860 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
861 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
862 goto give_sigsegv;
863 }
bellard66fb9762003-03-23 01:06:05 +0000864
865 /* Set up to return from userspace. If provided, use a stub
866 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000867 if (ka->sa_flags & TARGET_SA_RESTORER) {
868 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000869 } else {
bellard775b58d2007-11-11 16:22:17 +0000870 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000871 abi_ulong retcode_addr;
872 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
873 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000874 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000875 val16 = 0xb858;
876 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000877 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000878 val16 = 0x80cd;
879 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000880 }
881
882 if (err)
883 goto give_sigsegv;
884
885 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000886 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000887 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000888
889 cpu_x86_load_seg(env, R_DS, __USER_DS);
890 cpu_x86_load_seg(env, R_ES, __USER_DS);
891 cpu_x86_load_seg(env, R_SS, __USER_DS);
892 cpu_x86_load_seg(env, R_CS, __USER_CS);
893 env->eflags &= ~TF_MASK;
894
bellard579a97f2007-11-11 14:26:47 +0000895 unlock_user_struct(frame, frame_addr, 1);
896
bellard66fb9762003-03-23 01:06:05 +0000897 return;
898
899give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000900 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000901 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000902 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000903 force_sig(TARGET_SIGSEGV /* , current */);
904}
905
bellard579a97f2007-11-11 14:26:47 +0000906/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000907static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500908 target_siginfo_t *info,
909 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000910{
bellard28be6232007-11-11 22:23:38 +0000911 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000912 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000913 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000914
bellard579a97f2007-11-11 14:26:47 +0000915 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000916
bellard579a97f2007-11-11 14:26:47 +0000917 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000918 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000919
thsc3b5bc82007-12-02 06:31:25 +0000920 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000921 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000922 addr = frame_addr + offsetof(struct rt_sigframe, info);
923 err |= __put_user(addr, &frame->pinfo);
924 addr = frame_addr + offsetof(struct rt_sigframe, uc);
925 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000926 err |= copy_siginfo_to_user(&frame->info, info);
927 if (err)
928 goto give_sigsegv;
929
930 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000931 err |= __put_user(0, &frame->uc.tuc_flags);
932 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000933 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000934 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000935 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000936 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000937 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000938 &frame->uc.tuc_stack.ss_size);
939 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000940 env, set->sig[0],
941 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000942 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000943 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000944 goto give_sigsegv;
945 }
bellard66fb9762003-03-23 01:06:05 +0000946
947 /* Set up to return from userspace. If provided, use a stub
948 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000949 if (ka->sa_flags & TARGET_SA_RESTORER) {
950 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000951 } else {
bellard775b58d2007-11-11 16:22:17 +0000952 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000953 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
954 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000955 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000956 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000957 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000958 val16 = 0x80cd;
959 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000960 }
961
962 if (err)
963 goto give_sigsegv;
964
965 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000966 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000967 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000968
969 cpu_x86_load_seg(env, R_DS, __USER_DS);
970 cpu_x86_load_seg(env, R_ES, __USER_DS);
971 cpu_x86_load_seg(env, R_SS, __USER_DS);
972 cpu_x86_load_seg(env, R_CS, __USER_CS);
973 env->eflags &= ~TF_MASK;
974
bellard579a97f2007-11-11 14:26:47 +0000975 unlock_user_struct(frame, frame_addr, 1);
976
bellard66fb9762003-03-23 01:06:05 +0000977 return;
978
979give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000980 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000981 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000982 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000983 force_sig(TARGET_SIGSEGV /* , current */);
984}
985
986static int
987restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
988{
989 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000990 abi_ulong fpstate_addr;
991 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000992
bellard28be6232007-11-11 22:23:38 +0000993 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
994 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
995 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
996 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +0000997
bellard28be6232007-11-11 22:23:38 +0000998 env->regs[R_EDI] = tswapl(sc->edi);
999 env->regs[R_ESI] = tswapl(sc->esi);
1000 env->regs[R_EBP] = tswapl(sc->ebp);
1001 env->regs[R_ESP] = tswapl(sc->esp);
1002 env->regs[R_EBX] = tswapl(sc->ebx);
1003 env->regs[R_EDX] = tswapl(sc->edx);
1004 env->regs[R_ECX] = tswapl(sc->ecx);
1005 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001006
Mike McCormack9a826d72011-06-01 15:14:37 +09001007 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1008 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001009
bellard28be6232007-11-11 22:23:38 +00001010 tmpflags = tswapl(sc->eflags);
1011 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1012 // regs->orig_eax = -1; /* disable syscall checks */
1013
1014 fpstate_addr = tswapl(sc->fpstate);
1015 if (fpstate_addr != 0) {
1016 if (!access_ok(VERIFY_READ, fpstate_addr,
1017 sizeof(struct target_fpstate)))
1018 goto badframe;
1019 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001020 }
1021
bellard28be6232007-11-11 22:23:38 +00001022 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001023 return err;
bellard66fb9762003-03-23 01:06:05 +00001024badframe:
1025 return 1;
bellard66fb9762003-03-23 01:06:05 +00001026}
1027
1028long do_sigreturn(CPUX86State *env)
1029{
bellard579a97f2007-11-11 14:26:47 +00001030 struct sigframe *frame;
1031 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001032 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001033 sigset_t set;
1034 int eax, i;
1035
bellard447db212003-05-10 15:10:36 +00001036#if defined(DEBUG_SIGNAL)
1037 fprintf(stderr, "do_sigreturn\n");
1038#endif
bellard579a97f2007-11-11 14:26:47 +00001039 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1040 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001041 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +00001042 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
1043 goto badframe;
1044 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1045 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
1046 goto badframe;
1047 }
bellard66fb9762003-03-23 01:06:05 +00001048
bellard92319442004-06-19 16:58:13 +00001049 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +00001050 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001051
bellard66fb9762003-03-23 01:06:05 +00001052 /* restore registers */
1053 if (restore_sigcontext(env, &frame->sc, &eax))
1054 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001055 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001056 return eax;
1057
1058badframe:
bellard579a97f2007-11-11 14:26:47 +00001059 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001060 force_sig(TARGET_SIGSEGV);
1061 return 0;
1062}
1063
1064long do_rt_sigreturn(CPUX86State *env)
1065{
bellard28be6232007-11-11 22:23:38 +00001066 abi_ulong frame_addr;
1067 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001068 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001069 int eax;
1070
bellard28be6232007-11-11 22:23:38 +00001071 frame_addr = env->regs[R_ESP] - 4;
1072 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1073 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001074 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +00001075 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001076
bellardb8076a72005-04-07 22:20:31 +00001077 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001078 goto badframe;
1079
bellard28be6232007-11-11 22:23:38 +00001080 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1081 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001082 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001083
bellard28be6232007-11-11 22:23:38 +00001084 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001085 return eax;
1086
1087badframe:
bellard28be6232007-11-11 22:23:38 +00001088 unlock_user_struct(frame, frame_addr, 0);
1089 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001090 return 0;
1091}
1092
bellard43fff232003-07-09 19:31:39 +00001093#elif defined(TARGET_ARM)
1094
1095struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001096 abi_ulong trap_no;
1097 abi_ulong error_code;
1098 abi_ulong oldmask;
1099 abi_ulong arm_r0;
1100 abi_ulong arm_r1;
1101 abi_ulong arm_r2;
1102 abi_ulong arm_r3;
1103 abi_ulong arm_r4;
1104 abi_ulong arm_r5;
1105 abi_ulong arm_r6;
1106 abi_ulong arm_r7;
1107 abi_ulong arm_r8;
1108 abi_ulong arm_r9;
1109 abi_ulong arm_r10;
1110 abi_ulong arm_fp;
1111 abi_ulong arm_ip;
1112 abi_ulong arm_sp;
1113 abi_ulong arm_lr;
1114 abi_ulong arm_pc;
1115 abi_ulong arm_cpsr;
1116 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001117};
1118
pbrooka745ec62008-05-06 15:36:17 +00001119struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001120 abi_ulong tuc_flags;
1121 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001122 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001123 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001124 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001125};
1126
pbrooka745ec62008-05-06 15:36:17 +00001127struct target_ucontext_v2 {
1128 abi_ulong tuc_flags;
1129 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001130 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001131 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001132 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001133 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001134 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1135};
1136
Peter Maydell0d871bd2010-11-24 15:20:05 +00001137struct target_user_vfp {
1138 uint64_t fpregs[32];
1139 abi_ulong fpscr;
1140};
1141
1142struct target_user_vfp_exc {
1143 abi_ulong fpexc;
1144 abi_ulong fpinst;
1145 abi_ulong fpinst2;
1146};
1147
1148struct target_vfp_sigframe {
1149 abi_ulong magic;
1150 abi_ulong size;
1151 struct target_user_vfp ufp;
1152 struct target_user_vfp_exc ufp_exc;
1153} __attribute__((__aligned__(8)));
1154
Peter Maydell08e11252010-11-24 15:20:07 +00001155struct target_iwmmxt_sigframe {
1156 abi_ulong magic;
1157 abi_ulong size;
1158 uint64_t regs[16];
1159 /* Note that not all the coprocessor control registers are stored here */
1160 uint32_t wcssf;
1161 uint32_t wcasf;
1162 uint32_t wcgr0;
1163 uint32_t wcgr1;
1164 uint32_t wcgr2;
1165 uint32_t wcgr3;
1166} __attribute__((__aligned__(8)));
1167
Peter Maydell0d871bd2010-11-24 15:20:05 +00001168#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001169#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001170
pbrooka8c33202008-05-07 23:22:46 +00001171struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001172{
1173 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001174 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1175 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001176};
1177
pbrooka8c33202008-05-07 23:22:46 +00001178struct sigframe_v2
1179{
1180 struct target_ucontext_v2 uc;
1181 abi_ulong retcode;
1182};
1183
pbrooka745ec62008-05-06 15:36:17 +00001184struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001185{
bellardf8b0aa22007-11-11 23:03:42 +00001186 abi_ulong pinfo;
1187 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001188 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001189 struct target_ucontext_v1 uc;
1190 abi_ulong retcode;
1191};
1192
1193struct rt_sigframe_v2
1194{
1195 struct target_siginfo info;
1196 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001197 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001198};
1199
1200#define TARGET_CONFIG_CPU_32 1
1201
1202/*
1203 * For ARM syscalls, we encode the syscall number into the instruction.
1204 */
1205#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1206#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1207
1208/*
1209 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1210 * need two 16-bit instructions.
1211 */
1212#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1213#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1214
blueswir1992f48a2007-10-14 16:27:31 +00001215static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001216 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1217 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1218};
1219
1220
bellard43fff232003-07-09 19:31:39 +00001221#define __get_user_error(x,p,e) __get_user(x, p)
1222
Andreas Färber05390242012-02-25 03:37:53 +01001223static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001224{
1225 return 1;
1226}
1227
pbrooka8c33202008-05-07 23:22:46 +00001228static void
bellard43fff232003-07-09 19:31:39 +00001229setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001230 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001231{
pbrooka8c33202008-05-07 23:22:46 +00001232 __put_user(env->regs[0], &sc->arm_r0);
1233 __put_user(env->regs[1], &sc->arm_r1);
1234 __put_user(env->regs[2], &sc->arm_r2);
1235 __put_user(env->regs[3], &sc->arm_r3);
1236 __put_user(env->regs[4], &sc->arm_r4);
1237 __put_user(env->regs[5], &sc->arm_r5);
1238 __put_user(env->regs[6], &sc->arm_r6);
1239 __put_user(env->regs[7], &sc->arm_r7);
1240 __put_user(env->regs[8], &sc->arm_r8);
1241 __put_user(env->regs[9], &sc->arm_r9);
1242 __put_user(env->regs[10], &sc->arm_r10);
1243 __put_user(env->regs[11], &sc->arm_fp);
1244 __put_user(env->regs[12], &sc->arm_ip);
1245 __put_user(env->regs[13], &sc->arm_sp);
1246 __put_user(env->regs[14], &sc->arm_lr);
1247 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001248#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001249 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001250#endif
1251
pbrooka8c33202008-05-07 23:22:46 +00001252 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1253 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1254 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1255 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001256}
1257
bellard579a97f2007-11-11 14:26:47 +00001258static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001259get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001260{
1261 unsigned long sp = regs->regs[13];
1262
bellard43fff232003-07-09 19:31:39 +00001263 /*
1264 * This is the X/Open sanctioned signal stack switching.
1265 */
pbrook624f7972008-05-31 16:11:38 +00001266 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001267 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001268 /*
1269 * ATPCS B01 mandates 8-byte alignment
1270 */
bellard579a97f2007-11-11 14:26:47 +00001271 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001272}
1273
1274static int
Andreas Färber05390242012-02-25 03:37:53 +01001275setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001276 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001277{
pbrook624f7972008-05-31 16:11:38 +00001278 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001279 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001280 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001281 uint32_t cpsr = cpsr_read(env);
1282
1283 cpsr &= ~CPSR_IT;
1284 if (thumb) {
1285 cpsr |= CPSR_T;
1286 } else {
1287 cpsr &= ~CPSR_T;
1288 }
bellard43fff232003-07-09 19:31:39 +00001289
pbrook624f7972008-05-31 16:11:38 +00001290 if (ka->sa_flags & TARGET_SA_RESTORER) {
1291 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001292 } else {
1293 unsigned int idx = thumb;
1294
pbrook624f7972008-05-31 16:11:38 +00001295 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001296 idx += 2;
1297
1298 if (__put_user(retcodes[idx], rc))
1299 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001300
bellardf8b0aa22007-11-11 23:03:42 +00001301 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001302 }
1303
1304 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001305 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001306 env->regs[14] = retcode;
1307 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001308 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001309
1310 return 0;
1311}
1312
Andreas Färber05390242012-02-25 03:37:53 +01001313static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001314{
1315 int i;
1316 struct target_vfp_sigframe *vfpframe;
1317 vfpframe = (struct target_vfp_sigframe *)regspace;
1318 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1319 __put_user(sizeof(*vfpframe), &vfpframe->size);
1320 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001321 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001322 }
1323 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1324 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1325 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1326 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1327 return (abi_ulong*)(vfpframe+1);
1328}
1329
Andreas Färber05390242012-02-25 03:37:53 +01001330static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1331 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001332{
1333 int i;
1334 struct target_iwmmxt_sigframe *iwmmxtframe;
1335 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1336 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1337 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1338 for (i = 0; i < 16; i++) {
1339 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1340 }
1341 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1342 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1343 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1344 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1345 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1346 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1347 return (abi_ulong*)(iwmmxtframe+1);
1348}
1349
pbrooka8c33202008-05-07 23:22:46 +00001350static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001351 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001352{
pbrooka8c33202008-05-07 23:22:46 +00001353 struct target_sigaltstack stack;
1354 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001355 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001356
1357 /* Clear all the bits of the ucontext we don't use. */
1358 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1359
1360 memset(&stack, 0, sizeof(stack));
1361 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1362 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1363 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1364 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1365
1366 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001367 /* Save coprocessor signal frame. */
1368 regspace = uc->tuc_regspace;
1369 if (arm_feature(env, ARM_FEATURE_VFP)) {
1370 regspace = setup_sigframe_v2_vfp(regspace, env);
1371 }
Peter Maydell08e11252010-11-24 15:20:07 +00001372 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1373 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1374 }
1375
Peter Maydell0d871bd2010-11-24 15:20:05 +00001376 /* Write terminating magic word */
1377 __put_user(0, regspace);
1378
pbrooka8c33202008-05-07 23:22:46 +00001379 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1380 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1381 }
1382}
1383
1384/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001385static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001386 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001387{
1388 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001389 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001390 int i;
bellard43fff232003-07-09 19:31:39 +00001391
bellard579a97f2007-11-11 14:26:47 +00001392 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1393 return;
1394
pbrooka8c33202008-05-07 23:22:46 +00001395 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001396
bellard92319442004-06-19 16:58:13 +00001397 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1398 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001399 goto end;
bellard43fff232003-07-09 19:31:39 +00001400 }
1401
pbrooka8c33202008-05-07 23:22:46 +00001402 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1403 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001404
1405end:
1406 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001407}
1408
pbrook624f7972008-05-31 16:11:38 +00001409static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001410 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001411{
1412 struct sigframe_v2 *frame;
1413 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1414
1415 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1416 return;
1417
1418 setup_sigframe_v2(&frame->uc, set, regs);
1419
1420 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1421 frame_addr + offsetof(struct sigframe_v2, retcode));
1422
1423 unlock_user_struct(frame, frame_addr, 1);
1424}
1425
pbrook624f7972008-05-31 16:11:38 +00001426static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001427 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001428{
1429 if (get_osversion() >= 0x020612) {
1430 setup_frame_v2(usig, ka, set, regs);
1431 } else {
1432 setup_frame_v1(usig, ka, set, regs);
1433 }
bellard43fff232003-07-09 19:31:39 +00001434}
1435
bellard579a97f2007-11-11 14:26:47 +00001436/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001437static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001438 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001439 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001440{
pbrooka745ec62008-05-06 15:36:17 +00001441 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001442 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001443 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001444 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001445 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001446
bellard579a97f2007-11-11 14:26:47 +00001447 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001448 return /* 1 */;
1449
pbrooka745ec62008-05-06 15:36:17 +00001450 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001451 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001452 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001453 __put_user(uc_addr, &frame->puc);
1454 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001455
1456 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001457 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001458
thsa04e1342007-09-27 13:57:58 +00001459 memset(&stack, 0, sizeof(stack));
1460 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1461 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1462 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001463 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001464
pbrooka8c33202008-05-07 23:22:46 +00001465 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001466 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001467 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001468 goto end;
bellard92319442004-06-19 16:58:13 +00001469 }
bellard43fff232003-07-09 19:31:39 +00001470
pbrooka8c33202008-05-07 23:22:46 +00001471 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1472 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001473
pbrooka8c33202008-05-07 23:22:46 +00001474 env->regs[1] = info_addr;
1475 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001476
1477end:
1478 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001479}
1480
pbrook624f7972008-05-31 16:11:38 +00001481static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001482 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001483 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001484{
1485 struct rt_sigframe_v2 *frame;
1486 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001487 abi_ulong info_addr, uc_addr;
1488
1489 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1490 return /* 1 */;
1491
1492 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1493 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001494 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001495
pbrooka8c33202008-05-07 23:22:46 +00001496 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001497
pbrooka8c33202008-05-07 23:22:46 +00001498 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1499 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001500
pbrooka8c33202008-05-07 23:22:46 +00001501 env->regs[1] = info_addr;
1502 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001503
bellard579a97f2007-11-11 14:26:47 +00001504 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001505}
1506
pbrook624f7972008-05-31 16:11:38 +00001507static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001508 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001509 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001510{
1511 if (get_osversion() >= 0x020612) {
1512 setup_rt_frame_v2(usig, ka, info, set, env);
1513 } else {
1514 setup_rt_frame_v1(usig, ka, info, set, env);
1515 }
1516}
1517
bellard43fff232003-07-09 19:31:39 +00001518static int
Andreas Färber05390242012-02-25 03:37:53 +01001519restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001520{
1521 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001522 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001523
1524 __get_user_error(env->regs[0], &sc->arm_r0, err);
1525 __get_user_error(env->regs[1], &sc->arm_r1, err);
1526 __get_user_error(env->regs[2], &sc->arm_r2, err);
1527 __get_user_error(env->regs[3], &sc->arm_r3, err);
1528 __get_user_error(env->regs[4], &sc->arm_r4, err);
1529 __get_user_error(env->regs[5], &sc->arm_r5, err);
1530 __get_user_error(env->regs[6], &sc->arm_r6, err);
1531 __get_user_error(env->regs[7], &sc->arm_r7, err);
1532 __get_user_error(env->regs[8], &sc->arm_r8, err);
1533 __get_user_error(env->regs[9], &sc->arm_r9, err);
1534 __get_user_error(env->regs[10], &sc->arm_r10, err);
1535 __get_user_error(env->regs[11], &sc->arm_fp, err);
1536 __get_user_error(env->regs[12], &sc->arm_ip, err);
1537 __get_user_error(env->regs[13], &sc->arm_sp, err);
1538 __get_user_error(env->regs[14], &sc->arm_lr, err);
1539 __get_user_error(env->regs[15], &sc->arm_pc, err);
1540#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001541 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001542 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001543#endif
1544
1545 err |= !valid_user_regs(env);
1546
1547 return err;
1548}
1549
Andreas Färber05390242012-02-25 03:37:53 +01001550static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001551{
bellardf8b0aa22007-11-11 23:03:42 +00001552 abi_ulong frame_addr;
pbrooka8c33202008-05-07 23:22:46 +00001553 struct sigframe_v1 *frame;
Anthony Liguoric227f092009-10-01 16:12:16 -05001554 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001555 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001556 int i;
bellard43fff232003-07-09 19:31:39 +00001557
1558 /*
1559 * Since we stacked the signal on a 64-bit boundary,
1560 * then 'sp' should be word aligned here. If it's
1561 * not, then the user is trying to mess with us.
1562 */
1563 if (env->regs[13] & 7)
1564 goto badframe;
1565
bellardf8b0aa22007-11-11 23:03:42 +00001566 frame_addr = env->regs[13];
1567 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1568 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001569
bellard92319442004-06-19 16:58:13 +00001570 if (__get_user(set.sig[0], &frame->sc.oldmask))
1571 goto badframe;
1572 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1573 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1574 goto badframe;
1575 }
bellard43fff232003-07-09 19:31:39 +00001576
bellard92319442004-06-19 16:58:13 +00001577 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001578 sigprocmask(SIG_SETMASK, &host_set, NULL);
1579
1580 if (restore_sigcontext(env, &frame->sc))
1581 goto badframe;
1582
1583#if 0
1584 /* Send SIGTRAP if we're single-stepping */
1585 if (ptrace_cancel_bpt(current))
1586 send_sig(SIGTRAP, current, 1);
1587#endif
bellardf8b0aa22007-11-11 23:03:42 +00001588 unlock_user_struct(frame, frame_addr, 0);
1589 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001590
1591badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001592 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001593 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001594 return 0;
1595}
1596
Andreas Färber05390242012-02-25 03:37:53 +01001597static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001598{
1599 int i;
1600 abi_ulong magic, sz;
1601 uint32_t fpscr, fpexc;
1602 struct target_vfp_sigframe *vfpframe;
1603 vfpframe = (struct target_vfp_sigframe *)regspace;
1604
1605 __get_user(magic, &vfpframe->magic);
1606 __get_user(sz, &vfpframe->size);
1607 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1608 return 0;
1609 }
1610 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001611 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001612 }
1613 __get_user(fpscr, &vfpframe->ufp.fpscr);
1614 vfp_set_fpscr(env, fpscr);
1615 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1616 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1617 * and the exception flag is cleared
1618 */
1619 fpexc |= (1 << 30);
1620 fpexc &= ~((1 << 31) | (1 << 28));
1621 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1622 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1623 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1624 return (abi_ulong*)(vfpframe + 1);
1625}
1626
Andreas Färber05390242012-02-25 03:37:53 +01001627static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1628 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001629{
1630 int i;
1631 abi_ulong magic, sz;
1632 struct target_iwmmxt_sigframe *iwmmxtframe;
1633 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1634
1635 __get_user(magic, &iwmmxtframe->magic);
1636 __get_user(sz, &iwmmxtframe->size);
1637 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1638 return 0;
1639 }
1640 for (i = 0; i < 16; i++) {
1641 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1642 }
1643 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1644 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1645 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1646 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1647 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1648 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1649 return (abi_ulong*)(iwmmxtframe + 1);
1650}
1651
Andreas Färber05390242012-02-25 03:37:53 +01001652static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001653 struct target_ucontext_v2 *uc)
1654{
1655 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001656 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001657
1658 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1659 sigprocmask(SIG_SETMASK, &host_set, NULL);
1660
1661 if (restore_sigcontext(env, &uc->tuc_mcontext))
1662 return 1;
1663
Peter Maydell5f9099d2010-11-24 15:20:06 +00001664 /* Restore coprocessor signal frame */
1665 regspace = uc->tuc_regspace;
1666 if (arm_feature(env, ARM_FEATURE_VFP)) {
1667 regspace = restore_sigframe_v2_vfp(env, regspace);
1668 if (!regspace) {
1669 return 1;
1670 }
1671 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001672 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1673 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1674 if (!regspace) {
1675 return 1;
1676 }
1677 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001678
pbrooka8c33202008-05-07 23:22:46 +00001679 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1680 return 1;
1681
1682#if 0
1683 /* Send SIGTRAP if we're single-stepping */
1684 if (ptrace_cancel_bpt(current))
1685 send_sig(SIGTRAP, current, 1);
1686#endif
1687
1688 return 0;
1689}
1690
Andreas Färber05390242012-02-25 03:37:53 +01001691static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001692{
1693 abi_ulong frame_addr;
1694 struct sigframe_v2 *frame;
1695
1696 /*
1697 * Since we stacked the signal on a 64-bit boundary,
1698 * then 'sp' should be word aligned here. If it's
1699 * not, then the user is trying to mess with us.
1700 */
1701 if (env->regs[13] & 7)
1702 goto badframe;
1703
1704 frame_addr = env->regs[13];
1705 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1706 goto badframe;
1707
1708 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1709 goto badframe;
1710
1711 unlock_user_struct(frame, frame_addr, 0);
1712 return env->regs[0];
1713
1714badframe:
1715 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001716 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00001717 return 0;
1718}
1719
Andreas Färber05390242012-02-25 03:37:53 +01001720long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001721{
1722 if (get_osversion() >= 0x020612) {
1723 return do_sigreturn_v2(env);
1724 } else {
1725 return do_sigreturn_v1(env);
1726 }
1727}
1728
Andreas Färber05390242012-02-25 03:37:53 +01001729static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001730{
bellardf8b0aa22007-11-11 23:03:42 +00001731 abi_ulong frame_addr;
pbrooka745ec62008-05-06 15:36:17 +00001732 struct rt_sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001733 sigset_t host_set;
1734
1735 /*
1736 * Since we stacked the signal on a 64-bit boundary,
1737 * then 'sp' should be word aligned here. If it's
1738 * not, then the user is trying to mess with us.
1739 */
1740 if (env->regs[13] & 7)
1741 goto badframe;
1742
bellardf8b0aa22007-11-11 23:03:42 +00001743 frame_addr = env->regs[13];
1744 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1745 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001746
bellardb8076a72005-04-07 22:20:31 +00001747 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00001748 sigprocmask(SIG_SETMASK, &host_set, NULL);
1749
bellardb8076a72005-04-07 22:20:31 +00001750 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00001751 goto badframe;
1752
pbrooka745ec62008-05-06 15:36:17 +00001753 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 +00001754 goto badframe;
1755
bellard43fff232003-07-09 19:31:39 +00001756#if 0
1757 /* Send SIGTRAP if we're single-stepping */
1758 if (ptrace_cancel_bpt(current))
1759 send_sig(SIGTRAP, current, 1);
1760#endif
bellardf8b0aa22007-11-11 23:03:42 +00001761 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001762 return env->regs[0];
1763
1764badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001765 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001766 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001767 return 0;
1768}
1769
Andreas Färber05390242012-02-25 03:37:53 +01001770static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001771{
1772 abi_ulong frame_addr;
1773 struct rt_sigframe_v2 *frame;
pbrooka745ec62008-05-06 15:36:17 +00001774
1775 /*
1776 * Since we stacked the signal on a 64-bit boundary,
1777 * then 'sp' should be word aligned here. If it's
1778 * not, then the user is trying to mess with us.
1779 */
1780 if (env->regs[13] & 7)
1781 goto badframe;
1782
1783 frame_addr = env->regs[13];
1784 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1785 goto badframe;
1786
pbrooka8c33202008-05-07 23:22:46 +00001787 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1788 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00001789
pbrooka745ec62008-05-06 15:36:17 +00001790 unlock_user_struct(frame, frame_addr, 0);
1791 return env->regs[0];
1792
1793badframe:
1794 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001795 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00001796 return 0;
1797}
1798
Andreas Färber05390242012-02-25 03:37:53 +01001799long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001800{
1801 if (get_osversion() >= 0x020612) {
1802 return do_rt_sigreturn_v2(env);
1803 } else {
1804 return do_rt_sigreturn_v1(env);
1805 }
1806}
1807
bellard6d5e2162004-09-30 22:04:13 +00001808#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00001809
bellard6d5e2162004-09-30 22:04:13 +00001810#define __SUNOS_MAXWIN 31
1811
1812/* This is what SunOS does, so shall I. */
1813struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001814 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00001815
blueswir1992f48a2007-10-14 16:27:31 +00001816 abi_ulong sigc_mask; /* sigmask to restore */
1817 abi_ulong sigc_sp; /* stack pointer */
1818 abi_ulong sigc_pc; /* program counter */
1819 abi_ulong sigc_npc; /* next program counter */
1820 abi_ulong sigc_psr; /* for condition codes etc */
1821 abi_ulong sigc_g1; /* User uses these two registers */
1822 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00001823
1824 /* Now comes information regarding the users window set
1825 * at the time of the signal.
1826 */
blueswir1992f48a2007-10-14 16:27:31 +00001827 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00001828
1829 /* stack ptrs for each regwin buf */
1830 char *sigc_spbuf[__SUNOS_MAXWIN];
1831
1832 /* Windows to restore after signal */
1833 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001834 abi_ulong locals[8];
1835 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00001836 } sigc_wbuf[__SUNOS_MAXWIN];
1837};
1838/* A Sparc stack frame */
1839struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00001840 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00001841 abi_ulong ins[8];
1842 /* It's simpler to treat fp and callers_pc as elements of ins[]
1843 * since we never need to access them ourselves.
1844 */
bellard6d5e2162004-09-30 22:04:13 +00001845 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00001846 abi_ulong xargs[6];
1847 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00001848};
1849
1850typedef struct {
1851 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001852 abi_ulong psr;
1853 abi_ulong pc;
1854 abi_ulong npc;
1855 abi_ulong y;
1856 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00001857 } si_regs;
1858 int si_mask;
1859} __siginfo_t;
1860
1861typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00001862 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00001863 unsigned long si_fsr;
1864 unsigned long si_fpqdepth;
1865 struct {
1866 unsigned long *insn_addr;
1867 unsigned long insn;
1868 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05001869} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00001870
1871
1872struct target_signal_frame {
1873 struct sparc_stackf ss;
1874 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00001875 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00001876 abi_ulong insns[2] __attribute__ ((aligned (8)));
1877 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
1878 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05001879 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001880};
1881struct target_rt_signal_frame {
1882 struct sparc_stackf ss;
1883 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00001884 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00001885 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00001886 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00001887 unsigned int insns[2];
1888 stack_t stack;
1889 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05001890 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001891};
1892
bellarde80cfcf2004-12-19 23:18:01 +00001893#define UREG_O0 16
1894#define UREG_O6 22
1895#define UREG_I0 0
1896#define UREG_I1 1
1897#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00001898#define UREG_I3 3
1899#define UREG_I4 4
1900#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00001901#define UREG_I6 6
1902#define UREG_I7 7
1903#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00001904#define UREG_FP UREG_I6
1905#define UREG_SP UREG_O6
1906
pbrook624f7972008-05-31 16:11:38 +00001907static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01001908 CPUSPARCState *env,
1909 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00001910{
bellard459a4012007-11-11 19:45:10 +00001911 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00001912
1913 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00001914
1915 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00001916 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00001917 if (!on_sig_stack(sp)
1918 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
1919 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00001920 }
bellard459a4012007-11-11 19:45:10 +00001921 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00001922}
1923
1924static int
Andreas Färber05390242012-02-25 03:37:53 +01001925setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00001926{
1927 int err = 0, i;
1928
bellard6d5e2162004-09-30 22:04:13 +00001929 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00001930 err |= __put_user(env->pc, &si->si_regs.pc);
1931 err |= __put_user(env->npc, &si->si_regs.npc);
1932 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001933 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00001934 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
1935 }
bellarda315a142005-01-30 22:59:18 +00001936 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001937 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00001938 }
bellard6d5e2162004-09-30 22:04:13 +00001939 err |= __put_user(mask, &si->si_mask);
1940 return err;
1941}
bellarde80cfcf2004-12-19 23:18:01 +00001942
bellard80a9d032005-01-03 23:31:27 +00001943#if 0
bellard6d5e2162004-09-30 22:04:13 +00001944static int
1945setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001946 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00001947{
1948 int err = 0;
1949
1950 err |= __put_user(mask, &sc->sigc_mask);
1951 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
1952 err |= __put_user(env->pc, &sc->sigc_pc);
1953 err |= __put_user(env->npc, &sc->sigc_npc);
1954 err |= __put_user(env->psr, &sc->sigc_psr);
1955 err |= __put_user(env->gregs[1], &sc->sigc_g1);
1956 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
1957
1958 return err;
1959}
bellard80a9d032005-01-03 23:31:27 +00001960#endif
bellard6d5e2162004-09-30 22:04:13 +00001961#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
1962
pbrook624f7972008-05-31 16:11:38 +00001963static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001964 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00001965{
bellard459a4012007-11-11 19:45:10 +00001966 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001967 struct target_signal_frame *sf;
1968 int sigframe_size, err, i;
1969
1970 /* 1. Make sure everything is clean */
1971 //synchronize_user_stack();
1972
1973 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00001974 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00001975
bellard459a4012007-11-11 19:45:10 +00001976 sf = lock_user(VERIFY_WRITE, sf_addr,
1977 sizeof(struct target_signal_frame), 0);
1978 if (!sf)
1979 goto sigsegv;
1980
bellarde80cfcf2004-12-19 23:18:01 +00001981 //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 +00001982#if 0
1983 if (invalid_frame_pointer(sf, sigframe_size))
1984 goto sigill_and_return;
1985#endif
1986 /* 2. Save the current process state */
1987 err = setup___siginfo(&sf->info, env, set->sig[0]);
1988 err |= __put_user(0, &sf->extra_size);
1989
1990 //err |= save_fpu_state(regs, &sf->fpu_state);
1991 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
1992
1993 err |= __put_user(set->sig[0], &sf->info.si_mask);
1994 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
1995 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
1996 }
1997
bellarda315a142005-01-30 22:59:18 +00001998 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001999 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002000 }
bellarda315a142005-01-30 22:59:18 +00002001 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002002 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002003 }
bellard6d5e2162004-09-30 22:04:13 +00002004 if (err)
2005 goto sigsegv;
2006
2007 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002008 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002009 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002010 env->regwptr[UREG_I1] = sf_addr +
2011 offsetof(struct target_signal_frame, info);
2012 env->regwptr[UREG_I2] = sf_addr +
2013 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002014
2015 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002016 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002017 env->npc = (env->pc + 4);
2018 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002019 if (ka->sa_restorer)
2020 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002021 else {
bellard775b58d2007-11-11 16:22:17 +00002022 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002023
2024 env->regwptr[UREG_I7] = sf_addr +
2025 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002026
2027 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002028 val32 = 0x821020d8;
2029 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002030
2031 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002032 val32 = 0x91d02010;
2033 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002034 if (err)
2035 goto sigsegv;
2036
2037 /* Flush instruction space. */
2038 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002039 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002040 }
bellard459a4012007-11-11 19:45:10 +00002041 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002042 return;
bellard459a4012007-11-11 19:45:10 +00002043#if 0
2044sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002045 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002046#endif
bellard6d5e2162004-09-30 22:04:13 +00002047sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002048 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002049 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002050 force_sig(TARGET_SIGSEGV);
2051}
2052static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002053restore_fpu_state(CPUSPARCState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00002054{
2055 int err;
2056#if 0
2057#ifdef CONFIG_SMP
2058 if (current->flags & PF_USEDFPU)
2059 regs->psr &= ~PSR_EF;
2060#else
2061 if (current == last_task_used_math) {
2062 last_task_used_math = 0;
2063 regs->psr &= ~PSR_EF;
2064 }
2065#endif
2066 current->used_math = 1;
2067 current->flags &= ~PF_USEDFPU;
2068#endif
2069#if 0
2070 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
2071 return -EFAULT;
2072#endif
2073
bellardfafffae2006-10-28 12:09:16 +00002074 /* XXX: incorrect */
Blue Swirl8954bae2012-07-30 15:29:11 +00002075 err = copy_from_user(&env->fpr[0], fpu->si_float_regs[0],
2076 (sizeof(abi_ulong) * 32));
bellard6d5e2162004-09-30 22:04:13 +00002077 err |= __get_user(env->fsr, &fpu->si_fsr);
2078#if 0
2079 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
2080 if (current->thread.fpqdepth != 0)
2081 err |= __copy_from_user(&current->thread.fpqueue[0],
2082 &fpu->si_fpqueue[0],
2083 ((sizeof(unsigned long) +
2084 (sizeof(unsigned long *)))*16));
2085#endif
2086 return err;
2087}
2088
2089
pbrook624f7972008-05-31 16:11:38 +00002090static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002091 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002092 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002093{
2094 fprintf(stderr, "setup_rt_frame: not implemented\n");
2095}
2096
Andreas Färber05390242012-02-25 03:37:53 +01002097long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002098{
bellardf8b0aa22007-11-11 23:03:42 +00002099 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002100 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002101 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002102 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002103 sigset_t host_set;
bellarde80cfcf2004-12-19 23:18:01 +00002104 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00002105
bellardf8b0aa22007-11-11 23:03:42 +00002106 sf_addr = env->regwptr[UREG_FP];
2107 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2108 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002109#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002110 fprintf(stderr, "sigreturn\n");
2111 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 +00002112#endif
bellarde80cfcf2004-12-19 23:18:01 +00002113 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002114
2115 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002116
bellardf8b0aa22007-11-11 23:03:42 +00002117 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002118 goto segv_and_exit;
2119
2120 err = __get_user(pc, &sf->info.si_regs.pc);
2121 err |= __get_user(npc, &sf->info.si_regs.npc);
2122
bellard6d5e2162004-09-30 22:04:13 +00002123 if ((pc | npc) & 3)
2124 goto segv_and_exit;
2125
2126 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00002127 err |= __get_user(up_psr, &sf->info.si_regs.psr);
2128
bellard6d5e2162004-09-30 22:04:13 +00002129 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002130 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2131 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2132
2133 env->pc = pc;
2134 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00002135 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002136 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002137 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2138 }
bellarda315a142005-01-30 22:59:18 +00002139 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002140 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2141 }
bellard6d5e2162004-09-30 22:04:13 +00002142
Peter Maydell2aec3a22011-06-16 17:37:14 +01002143 /* FIXME: implement FPU save/restore:
2144 * __get_user(fpu_save, &sf->fpu_save);
2145 * if (fpu_save)
2146 * err |= restore_fpu_state(env, fpu_save);
2147 */
bellard6d5e2162004-09-30 22:04:13 +00002148
2149 /* This is pretty much atomic, no amount locking would prevent
2150 * the races which exist anyways.
2151 */
2152 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002153 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2154 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
2155 }
2156
2157 target_to_host_sigset_internal(&host_set, &set);
2158 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002159
2160 if (err)
2161 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002162 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002163 return env->regwptr[0];
2164
2165segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002166 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002167 force_sig(TARGET_SIGSEGV);
2168}
2169
Andreas Färber05390242012-02-25 03:37:53 +01002170long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002171{
2172 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002173 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002174}
2175
bellard459a4012007-11-11 19:45:10 +00002176#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002177#define MC_TSTATE 0
2178#define MC_PC 1
2179#define MC_NPC 2
2180#define MC_Y 3
2181#define MC_G1 4
2182#define MC_G2 5
2183#define MC_G3 6
2184#define MC_G4 7
2185#define MC_G5 8
2186#define MC_G6 9
2187#define MC_G7 10
2188#define MC_O0 11
2189#define MC_O1 12
2190#define MC_O2 13
2191#define MC_O3 14
2192#define MC_O4 15
2193#define MC_O5 16
2194#define MC_O6 17
2195#define MC_O7 18
2196#define MC_NGREG 19
2197
Anthony Liguoric227f092009-10-01 16:12:16 -05002198typedef abi_ulong target_mc_greg_t;
2199typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002200
2201struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002202 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002203 uint32_t mcfq_insn;
2204};
2205
2206struct target_mc_fpu {
2207 union {
2208 uint32_t sregs[32];
2209 uint64_t dregs[32];
2210 //uint128_t qregs[16];
2211 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002212 abi_ulong mcfpu_fsr;
2213 abi_ulong mcfpu_fprs;
2214 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002215 struct target_mc_fq *mcfpu_fq;
2216 unsigned char mcfpu_qcnt;
2217 unsigned char mcfpu_qentsz;
2218 unsigned char mcfpu_enab;
2219};
Anthony Liguoric227f092009-10-01 16:12:16 -05002220typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002221
2222typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002223 target_mc_gregset_t mc_gregs;
2224 target_mc_greg_t mc_fp;
2225 target_mc_greg_t mc_i7;
2226 target_mc_fpu_t mc_fpregs;
2227} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002228
2229struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002230 struct target_ucontext *tuc_link;
2231 abi_ulong tuc_flags;
2232 target_sigset_t tuc_sigmask;
2233 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002234};
2235
2236/* A V9 register window */
2237struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002238 abi_ulong locals[8];
2239 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002240};
2241
2242#define TARGET_STACK_BIAS 2047
2243
2244/* {set, get}context() needed for 64-bit SparcLinux userland. */
2245void sparc64_set_context(CPUSPARCState *env)
2246{
bellard459a4012007-11-11 19:45:10 +00002247 abi_ulong ucp_addr;
2248 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002249 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002250 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002251 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002252 int err;
2253 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002254
bellard459a4012007-11-11 19:45:10 +00002255 ucp_addr = env->regwptr[UREG_I0];
2256 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2257 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002258 grp = &ucp->tuc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002259 err = __get_user(pc, &((*grp)[MC_PC]));
2260 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002261 if (err || ((pc | npc) & 3))
2262 goto do_sigsegv;
2263 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002264 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002265 sigset_t set;
2266
2267 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002268 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002269 goto do_sigsegv;
2270 } else {
bellard459a4012007-11-11 19:45:10 +00002271 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002272 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002273 dst = target_set.sig;
Anthony Liguoric227f092009-10-01 16:12:16 -05002274 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002275 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002276 err |= __get_user(*dst, src);
blueswir15bfb56b2007-10-05 17:01:51 +00002277 if (err)
2278 goto do_sigsegv;
2279 }
2280 target_to_host_sigset_internal(&set, &target_set);
2281 sigprocmask(SIG_SETMASK, &set, NULL);
2282 }
2283 env->pc = pc;
2284 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002285 err |= __get_user(env->y, &((*grp)[MC_Y]));
2286 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002287 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002288 cpu_put_ccr(env, tstate >> 32);
2289 cpu_put_cwp64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002290 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2291 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2292 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2293 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2294 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2295 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2296 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2297 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2298 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2299 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2300 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2301 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2302 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2303 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2304 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002305
Aurelien Jarno60e99242010-03-29 02:12:51 +02002306 err |= __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2307 err |= __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002308
bellard459a4012007-11-11 19:45:10 +00002309 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2310 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2311 abi_ulong) != 0)
2312 goto do_sigsegv;
2313 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2314 abi_ulong) != 0)
2315 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002316 /* FIXME this does not match how the kernel handles the FPU in
2317 * its sparc64_set_context implementation. In particular the FPU
2318 * is only restored if fenab is non-zero in:
2319 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2320 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002321 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002322 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002323 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2324 for (i = 0; i < 64; i++, src++) {
2325 if (i & 1) {
2326 err |= __get_user(env->fpr[i/2].l.lower, src);
2327 } else {
2328 err |= __get_user(env->fpr[i/2].l.upper, src);
2329 }
2330 }
bellard459a4012007-11-11 19:45:10 +00002331 }
bellard579a97f2007-11-11 14:26:47 +00002332 err |= __get_user(env->fsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002333 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
bellard579a97f2007-11-11 14:26:47 +00002334 err |= __get_user(env->gsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002335 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002336 if (err)
2337 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002338 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002339 return;
2340 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002341 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002342 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002343}
2344
2345void sparc64_get_context(CPUSPARCState *env)
2346{
bellard459a4012007-11-11 19:45:10 +00002347 abi_ulong ucp_addr;
2348 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002349 target_mc_gregset_t *grp;
2350 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002351 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002352 int err;
2353 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002354 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002355 sigset_t set;
2356
bellard459a4012007-11-11 19:45:10 +00002357 ucp_addr = env->regwptr[UREG_I0];
2358 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2359 goto do_sigsegv;
2360
Aurelien Jarno60e99242010-03-29 02:12:51 +02002361 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002362 grp = &mcp->mc_gregs;
2363
2364 /* Skip over the trap instruction, first. */
2365 env->pc = env->npc;
2366 env->npc += 4;
2367
2368 err = 0;
2369
2370 sigprocmask(0, NULL, &set);
2371 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002372 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002373 err |= __put_user(target_set.sig[0],
Aurelien Jarno60e99242010-03-29 02:12:51 +02002374 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002375 } else {
2376 abi_ulong *src, *dst;
2377 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002378 dst = ucp->tuc_sigmask.sig;
Anthony Liguoric227f092009-10-01 16:12:16 -05002379 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002380 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002381 err |= __put_user(*src, dst);
blueswir15bfb56b2007-10-05 17:01:51 +00002382 if (err)
2383 goto do_sigsegv;
2384 }
2385
bellard459a4012007-11-11 19:45:10 +00002386 /* XXX: tstate must be saved properly */
2387 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002388 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2389 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2390 err |= __put_user(env->y, &((*grp)[MC_Y]));
2391 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2392 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2393 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2394 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2395 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2396 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2397 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2398 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2399 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2400 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2401 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2402 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2403 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2404 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2405 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002406
bellard459a4012007-11-11 19:45:10 +00002407 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2408 fp = i7 = 0;
2409 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2410 abi_ulong) != 0)
2411 goto do_sigsegv;
2412 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2413 abi_ulong) != 0)
2414 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002415 err |= __put_user(fp, &(mcp->mc_fp));
2416 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002417
bellard459a4012007-11-11 19:45:10 +00002418 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002419 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2420 for (i = 0; i < 64; i++, dst++) {
2421 if (i & 1) {
2422 err |= __put_user(env->fpr[i/2].l.lower, dst);
2423 } else {
2424 err |= __put_user(env->fpr[i/2].l.upper, dst);
2425 }
2426 }
bellard459a4012007-11-11 19:45:10 +00002427 }
bellard579a97f2007-11-11 14:26:47 +00002428 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2429 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2430 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002431
2432 if (err)
2433 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002434 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002435 return;
2436 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002437 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002438 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002439}
2440#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002441#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002442
Richard Hendersonff970902013-02-10 10:30:42 -08002443# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002444struct target_sigcontext {
2445 uint32_t sc_regmask; /* Unused */
2446 uint32_t sc_status;
2447 uint64_t sc_pc;
2448 uint64_t sc_regs[32];
2449 uint64_t sc_fpregs[32];
2450 uint32_t sc_ownedfp; /* Unused */
2451 uint32_t sc_fpc_csr;
2452 uint32_t sc_fpc_eir; /* Unused */
2453 uint32_t sc_used_math;
2454 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002455 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002456 uint64_t sc_mdhi;
2457 uint64_t sc_mdlo;
2458 target_ulong sc_hi1; /* Was sc_cause */
2459 target_ulong sc_lo1; /* Was sc_badvaddr */
2460 target_ulong sc_hi2; /* Was sc_sigset[4] */
2461 target_ulong sc_lo2;
2462 target_ulong sc_hi3;
2463 target_ulong sc_lo3;
2464};
Richard Hendersonff970902013-02-10 10:30:42 -08002465# else /* N32 || N64 */
2466struct target_sigcontext {
2467 uint64_t sc_regs[32];
2468 uint64_t sc_fpregs[32];
2469 uint64_t sc_mdhi;
2470 uint64_t sc_hi1;
2471 uint64_t sc_hi2;
2472 uint64_t sc_hi3;
2473 uint64_t sc_mdlo;
2474 uint64_t sc_lo1;
2475 uint64_t sc_lo2;
2476 uint64_t sc_lo3;
2477 uint64_t sc_pc;
2478 uint32_t sc_fpc_csr;
2479 uint32_t sc_used_math;
2480 uint32_t sc_dsp;
2481 uint32_t sc_reserved;
2482};
2483# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002484
2485struct sigframe {
2486 uint32_t sf_ass[4]; /* argument save space for o32 */
2487 uint32_t sf_code[2]; /* signal trampoline */
2488 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002489 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002490};
2491
pbrook0b1bcb02009-04-21 01:41:10 +00002492struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002493 target_ulong tuc_flags;
2494 target_ulong tuc_link;
2495 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002496 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002497 struct target_sigcontext tuc_mcontext;
2498 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002499};
2500
2501struct target_rt_sigframe {
2502 uint32_t rs_ass[4]; /* argument save space for o32 */
2503 uint32_t rs_code[2]; /* signal trampoline */
2504 struct target_siginfo rs_info;
2505 struct target_ucontext rs_uc;
2506};
2507
bellard106ec872006-06-27 21:08:10 +00002508/* Install trampoline to jump back from signal handler */
2509static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2510{
2511 int err;
2512
2513 /*
2514 * Set up the return code ...
2515 *
2516 * li v0, __NR__foo_sigreturn
2517 * syscall
2518 */
2519
2520 err = __put_user(0x24020000 + syscall, tramp + 0);
2521 err |= __put_user(0x0000000c , tramp + 1);
2522 /* flush_cache_sigtramp((unsigned long) tramp); */
2523 return err;
2524}
2525
2526static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002527setup_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002528{
2529 int err = 0;
2530
thsb5dc7732008-06-27 10:02:35 +00002531 err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002532
thsb5dc7732008-06-27 10:02:35 +00002533#define save_gp_reg(i) do { \
2534 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002535 } while(0)
2536 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
2537 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
2538 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
2539 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
2540 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
2541 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
2542 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
2543 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
2544 save_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002545#undef save_gp_reg
bellard106ec872006-06-27 21:08:10 +00002546
thsb5dc7732008-06-27 10:02:35 +00002547 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2548 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002549
2550 /* Not used yet, but might be useful if we ever have DSP suppport */
2551#if 0
2552 if (cpu_has_dsp) {
2553 err |= __put_user(mfhi1(), &sc->sc_hi1);
2554 err |= __put_user(mflo1(), &sc->sc_lo1);
2555 err |= __put_user(mfhi2(), &sc->sc_hi2);
2556 err |= __put_user(mflo2(), &sc->sc_lo2);
2557 err |= __put_user(mfhi3(), &sc->sc_hi3);
2558 err |= __put_user(mflo3(), &sc->sc_lo3);
2559 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2560 }
2561 /* same with 64 bit */
ths388bb212007-05-13 13:58:00 +00002562#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002563 err |= __put_user(regs->hi, &sc->sc_hi[0]);
2564 err |= __put_user(regs->lo, &sc->sc_lo[0]);
2565 if (cpu_has_dsp) {
2566 err |= __put_user(mfhi1(), &sc->sc_hi[1]);
2567 err |= __put_user(mflo1(), &sc->sc_lo[1]);
2568 err |= __put_user(mfhi2(), &sc->sc_hi[2]);
2569 err |= __put_user(mflo2(), &sc->sc_lo[2]);
2570 err |= __put_user(mfhi3(), &sc->sc_hi[3]);
2571 err |= __put_user(mflo3(), &sc->sc_lo[3]);
2572 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2573 }
ths388bb212007-05-13 13:58:00 +00002574#endif
2575#endif
bellard106ec872006-06-27 21:08:10 +00002576
ths388bb212007-05-13 13:58:00 +00002577#if 0
bellard106ec872006-06-27 21:08:10 +00002578 err |= __put_user(!!used_math(), &sc->sc_used_math);
2579
2580 if (!used_math())
2581 goto out;
2582
2583 /*
2584 * Save FPU state to signal context. Signal handler will "inherit"
2585 * current FPU state.
2586 */
2587 preempt_disable();
2588
2589 if (!is_fpu_owner()) {
2590 own_fpu();
2591 restore_fp(current);
2592 }
2593 err |= save_fp_context(sc);
2594
2595 preempt_enable();
2596 out:
2597#endif
2598 return err;
2599}
2600
2601static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002602restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002603{
2604 int err = 0;
2605
2606 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2607
thsb5dc7732008-06-27 10:02:35 +00002608 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2609 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002610
thsead93602007-09-06 00:18:15 +00002611#define restore_gp_reg(i) do { \
thsb5dc7732008-06-27 10:02:35 +00002612 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002613 } while(0)
2614 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
2615 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
2616 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
2617 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
2618 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
2619 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
2620 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
2621 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
2622 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
2623 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
2624 restore_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002625#undef restore_gp_reg
bellard106ec872006-06-27 21:08:10 +00002626
2627#if 0
2628 if (cpu_has_dsp) {
2629 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
2630 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
2631 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
2632 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
2633 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
2634 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2635 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2636 }
ths388bb212007-05-13 13:58:00 +00002637#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002638 err |= __get_user(regs->hi, &sc->sc_hi[0]);
2639 err |= __get_user(regs->lo, &sc->sc_lo[0]);
2640 if (cpu_has_dsp) {
2641 err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
2642 err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
2643 err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
2644 err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
2645 err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
2646 err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
2647 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2648 }
ths388bb212007-05-13 13:58:00 +00002649#endif
bellard106ec872006-06-27 21:08:10 +00002650
2651 err |= __get_user(used_math, &sc->sc_used_math);
2652 conditional_used_math(used_math);
2653
2654 preempt_disable();
2655
2656 if (used_math()) {
2657 /* restore fpu context if we have used it before */
2658 own_fpu();
2659 err |= restore_fp_context(sc);
2660 } else {
2661 /* signal handler may have used FPU. Give it up. */
2662 lose_fpu();
2663 }
2664
2665 preempt_enable();
2666#endif
2667 return err;
2668}
Richard Hendersonff970902013-02-10 10:30:42 -08002669
bellard106ec872006-06-27 21:08:10 +00002670/*
2671 * Determine which stack to use..
2672 */
bellard579a97f2007-11-11 14:26:47 +00002673static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002674get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002675{
2676 unsigned long sp;
2677
2678 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002679 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002680
2681 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002682 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002683 * above the user stack, 16-bytes before the next lowest
2684 * 16 byte boundary. Try to avoid trashing it.
2685 */
2686 sp -= 32;
2687
bellard106ec872006-06-27 21:08:10 +00002688 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002689 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002690 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2691 }
bellard106ec872006-06-27 21:08:10 +00002692
bellard579a97f2007-11-11 14:26:47 +00002693 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002694}
2695
Richard Hendersonff970902013-02-10 10:30:42 -08002696# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002697/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002698static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002699 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002700{
2701 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002702 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002703 int i;
2704
bellard579a97f2007-11-11 14:26:47 +00002705 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2706 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002707 goto give_sigsegv;
2708
2709 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2710
2711 if(setup_sigcontext(regs, &frame->sf_sc))
2712 goto give_sigsegv;
2713
2714 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2715 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2716 goto give_sigsegv;
2717 }
2718
2719 /*
2720 * Arguments to signal handler:
2721 *
2722 * a0 = signal number
2723 * a1 = 0 (should be cause)
2724 * a2 = pointer to struct sigcontext
2725 *
2726 * $25 and PC point to the signal handler, $29 points to the
2727 * struct sigframe.
2728 */
thsb5dc7732008-06-27 10:02:35 +00002729 regs->active_tc.gpr[ 4] = sig;
2730 regs->active_tc.gpr[ 5] = 0;
2731 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2732 regs->active_tc.gpr[29] = frame_addr;
2733 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002734 /* The original kernel code sets CP0_EPC to the handler
2735 * since it returns to userland using eret
2736 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002737 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
bellard579a97f2007-11-11 14:26:47 +00002738 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002739 return;
2740
2741give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002742 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002743 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002744}
2745
Andreas Färber05390242012-02-25 03:37:53 +01002746long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002747{
ths388bb212007-05-13 13:58:00 +00002748 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002749 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002750 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002751 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002752 int i;
bellard106ec872006-06-27 21:08:10 +00002753
2754#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002755 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002756#endif
thsb5dc7732008-06-27 10:02:35 +00002757 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002758 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002759 goto badframe;
2760
ths388bb212007-05-13 13:58:00 +00002761 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002762 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2763 goto badframe;
ths388bb212007-05-13 13:58:00 +00002764 }
bellard106ec872006-06-27 21:08:10 +00002765
ths388bb212007-05-13 13:58:00 +00002766 target_to_host_sigset_internal(&blocked, &target_set);
2767 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002768
ths388bb212007-05-13 13:58:00 +00002769 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002770 goto badframe;
2771
2772#if 0
ths388bb212007-05-13 13:58:00 +00002773 /*
2774 * Don't let your children do this ...
2775 */
2776 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002777 "move\t$29, %0\n\t"
2778 "j\tsyscall_exit"
2779 :/* no outputs */
2780 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002781 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002782#endif
ths3b46e622007-09-17 08:09:54 +00002783
thsb5dc7732008-06-27 10:02:35 +00002784 regs->active_tc.PC = regs->CP0_EPC;
ths388bb212007-05-13 13:58:00 +00002785 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002786 * maybe a problem with nested signals ? */
2787 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00002788 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00002789
2790badframe:
ths388bb212007-05-13 13:58:00 +00002791 force_sig(TARGET_SIGSEGV/*, current*/);
2792 return 0;
bellard106ec872006-06-27 21:08:10 +00002793}
Richard Hendersonff970902013-02-10 10:30:42 -08002794# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002795
pbrook624f7972008-05-31 16:11:38 +00002796static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002797 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002798 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00002799{
pbrook0b1bcb02009-04-21 01:41:10 +00002800 struct target_rt_sigframe *frame;
2801 abi_ulong frame_addr;
2802 int i;
2803
2804 frame_addr = get_sigframe(ka, env, sizeof(*frame));
2805 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2806 goto give_sigsegv;
2807
2808 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
2809
2810 copy_siginfo_to_user(&frame->rs_info, info);
2811
Aurelien Jarno60e99242010-03-29 02:12:51 +02002812 __put_user(0, &frame->rs_uc.tuc_flags);
2813 __put_user(0, &frame->rs_uc.tuc_link);
2814 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
2815 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00002816 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02002817 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00002818
Aurelien Jarno60e99242010-03-29 02:12:51 +02002819 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00002820
2821 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002822 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00002823 }
2824
2825 /*
2826 * Arguments to signal handler:
2827 *
2828 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00002829 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00002830 * a2 = pointer to struct ucontext
2831 *
2832 * $25 and PC point to the signal handler, $29 points to the
2833 * struct sigframe.
2834 */
2835 env->active_tc.gpr[ 4] = sig;
2836 env->active_tc.gpr[ 5] = frame_addr
2837 + offsetof(struct target_rt_sigframe, rs_info);
2838 env->active_tc.gpr[ 6] = frame_addr
2839 + offsetof(struct target_rt_sigframe, rs_uc);
2840 env->active_tc.gpr[29] = frame_addr;
2841 env->active_tc.gpr[31] = frame_addr
2842 + offsetof(struct target_rt_sigframe, rs_code);
2843 /* The original kernel code sets CP0_EPC to the handler
2844 * since it returns to userland using eret
2845 * we cannot do this here, and we must set PC directly */
2846 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
2847 unlock_user_struct(frame, frame_addr, 1);
2848 return;
2849
2850give_sigsegv:
2851 unlock_user_struct(frame, frame_addr, 1);
2852 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002853}
2854
Andreas Färber05390242012-02-25 03:37:53 +01002855long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00002856{
pbrook0b1bcb02009-04-21 01:41:10 +00002857 struct target_rt_sigframe *frame;
2858 abi_ulong frame_addr;
2859 sigset_t blocked;
2860
2861#if defined(DEBUG_SIGNAL)
2862 fprintf(stderr, "do_rt_sigreturn\n");
2863#endif
2864 frame_addr = env->active_tc.gpr[29];
2865 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2866 goto badframe;
2867
Aurelien Jarno60e99242010-03-29 02:12:51 +02002868 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
pbrook0b1bcb02009-04-21 01:41:10 +00002869 sigprocmask(SIG_SETMASK, &blocked, NULL);
2870
Aurelien Jarno60e99242010-03-29 02:12:51 +02002871 if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
pbrook0b1bcb02009-04-21 01:41:10 +00002872 goto badframe;
2873
2874 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02002875 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00002876 0, get_sp_from_cpustate(env)) == -EFAULT)
2877 goto badframe;
2878
2879 env->active_tc.PC = env->CP0_EPC;
2880 /* I am not sure this is right, but it seems to work
2881 * maybe a problem with nested signals ? */
2882 env->CP0_EPC = 0;
2883 return -TARGET_QEMU_ESIGRETURN;
2884
2885badframe:
2886 force_sig(TARGET_SIGSEGV/*, current*/);
2887 return 0;
bellard106ec872006-06-27 21:08:10 +00002888}
bellard6d5e2162004-09-30 22:04:13 +00002889
thsc3b5bc82007-12-02 06:31:25 +00002890#elif defined(TARGET_SH4)
2891
2892/*
2893 * code and data structures from linux kernel:
2894 * include/asm-sh/sigcontext.h
2895 * arch/sh/kernel/signal.c
2896 */
2897
2898struct target_sigcontext {
2899 target_ulong oldmask;
2900
2901 /* CPU registers */
2902 target_ulong sc_gregs[16];
2903 target_ulong sc_pc;
2904 target_ulong sc_pr;
2905 target_ulong sc_sr;
2906 target_ulong sc_gbr;
2907 target_ulong sc_mach;
2908 target_ulong sc_macl;
2909
2910 /* FPU registers */
2911 target_ulong sc_fpregs[16];
2912 target_ulong sc_xfpregs[16];
2913 unsigned int sc_fpscr;
2914 unsigned int sc_fpul;
2915 unsigned int sc_ownedfp;
2916};
2917
2918struct target_sigframe
2919{
2920 struct target_sigcontext sc;
2921 target_ulong extramask[TARGET_NSIG_WORDS-1];
2922 uint16_t retcode[3];
2923};
2924
2925
2926struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002927 target_ulong tuc_flags;
2928 struct target_ucontext *tuc_link;
2929 target_stack_t tuc_stack;
2930 struct target_sigcontext tuc_mcontext;
2931 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00002932};
2933
2934struct target_rt_sigframe
2935{
2936 struct target_siginfo info;
2937 struct target_ucontext uc;
2938 uint16_t retcode[3];
2939};
2940
2941
2942#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
2943#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
2944
pbrook624f7972008-05-31 16:11:38 +00002945static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002946 unsigned long sp, size_t frame_size)
2947{
pbrook624f7972008-05-31 16:11:38 +00002948 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00002949 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2950 }
2951
2952 return (sp - frame_size) & -8ul;
2953}
2954
2955static int setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01002956 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00002957{
2958 int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09002959 int i;
thsc3b5bc82007-12-02 06:31:25 +00002960
2961#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
2962 COPY(gregs[0]); COPY(gregs[1]);
2963 COPY(gregs[2]); COPY(gregs[3]);
2964 COPY(gregs[4]); COPY(gregs[5]);
2965 COPY(gregs[6]); COPY(gregs[7]);
2966 COPY(gregs[8]); COPY(gregs[9]);
2967 COPY(gregs[10]); COPY(gregs[11]);
2968 COPY(gregs[12]); COPY(gregs[13]);
2969 COPY(gregs[14]); COPY(gregs[15]);
2970 COPY(gbr); COPY(mach);
2971 COPY(macl); COPY(pr);
2972 COPY(sr); COPY(pc);
2973#undef COPY
2974
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09002975 for (i=0; i<16; i++) {
2976 err |= __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
2977 }
2978 err |= __put_user(regs->fpscr, &sc->sc_fpscr);
2979 err |= __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00002980
2981 /* non-iBCS2 extensions.. */
2982 err |= __put_user(mask, &sc->oldmask);
2983
2984 return err;
2985}
2986
Andreas Färber05390242012-02-25 03:37:53 +01002987static int restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09002988 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00002989{
2990 unsigned int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09002991 int i;
thsc3b5bc82007-12-02 06:31:25 +00002992
2993#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
2994 COPY(gregs[1]);
2995 COPY(gregs[2]); COPY(gregs[3]);
2996 COPY(gregs[4]); COPY(gregs[5]);
2997 COPY(gregs[6]); COPY(gregs[7]);
2998 COPY(gregs[8]); COPY(gregs[9]);
2999 COPY(gregs[10]); COPY(gregs[11]);
3000 COPY(gregs[12]); COPY(gregs[13]);
3001 COPY(gregs[14]); COPY(gregs[15]);
3002 COPY(gbr); COPY(mach);
3003 COPY(macl); COPY(pr);
3004 COPY(sr); COPY(pc);
3005#undef COPY
3006
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003007 for (i=0; i<16; i++) {
3008 err |= __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
3009 }
3010 err |= __get_user(regs->fpscr, &sc->sc_fpscr);
3011 err |= __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003012
3013 regs->tra = -1; /* disable syscall checks */
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003014 err |= __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003015 return err;
3016}
3017
pbrook624f7972008-05-31 16:11:38 +00003018static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003019 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003020{
3021 struct target_sigframe *frame;
3022 abi_ulong frame_addr;
3023 int i;
3024 int err = 0;
3025 int signal;
3026
3027 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3028 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3029 goto give_sigsegv;
3030
3031 signal = current_exec_domain_sig(sig);
3032
3033 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
3034
3035 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
3036 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
3037 }
3038
3039 /* Set up to return from userspace. If provided, use a stub
3040 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003041 if (ka->sa_flags & TARGET_SA_RESTORER) {
3042 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003043 } else {
3044 /* Generate return code (system call to sigreturn) */
3045 err |= __put_user(MOVW(2), &frame->retcode[0]);
3046 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3047 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
3048 regs->pr = (unsigned long) frame->retcode;
3049 }
3050
3051 if (err)
3052 goto give_sigsegv;
3053
3054 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003055 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003056 regs->gregs[4] = signal; /* Arg for signal handler */
3057 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003058 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003059 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003060
3061 unlock_user_struct(frame, frame_addr, 1);
3062 return;
3063
3064give_sigsegv:
3065 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003066 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003067}
3068
pbrook624f7972008-05-31 16:11:38 +00003069static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003070 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003071 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003072{
3073 struct target_rt_sigframe *frame;
3074 abi_ulong frame_addr;
3075 int i;
3076 int err = 0;
3077 int signal;
3078
3079 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3080 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3081 goto give_sigsegv;
3082
3083 signal = current_exec_domain_sig(sig);
3084
3085 err |= copy_siginfo_to_user(&frame->info, info);
3086
3087 /* Create the ucontext. */
Aurelien Jarno60e99242010-03-29 02:12:51 +02003088 err |= __put_user(0, &frame->uc.tuc_flags);
3089 err |= __put_user(0, (unsigned long *)&frame->uc.tuc_link);
balrog526ccb72008-07-16 12:13:52 +00003090 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003091 &frame->uc.tuc_stack.ss_sp);
thsc3b5bc82007-12-02 06:31:25 +00003092 err |= __put_user(sas_ss_flags(regs->gregs[15]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003093 &frame->uc.tuc_stack.ss_flags);
thsc3b5bc82007-12-02 06:31:25 +00003094 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003095 &frame->uc.tuc_stack.ss_size);
3096 err |= setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003097 regs, set->sig[0]);
3098 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003099 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003100 }
3101
3102 /* Set up to return from userspace. If provided, use a stub
3103 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003104 if (ka->sa_flags & TARGET_SA_RESTORER) {
3105 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003106 } else {
3107 /* Generate return code (system call to sigreturn) */
3108 err |= __put_user(MOVW(2), &frame->retcode[0]);
3109 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3110 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
3111 regs->pr = (unsigned long) frame->retcode;
3112 }
3113
3114 if (err)
3115 goto give_sigsegv;
3116
3117 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003118 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003119 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003120 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3121 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003122 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003123
3124 unlock_user_struct(frame, frame_addr, 1);
3125 return;
3126
3127give_sigsegv:
3128 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003129 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003130}
3131
Andreas Färber05390242012-02-25 03:37:53 +01003132long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003133{
3134 struct target_sigframe *frame;
3135 abi_ulong frame_addr;
3136 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003137 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003138 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003139 int i;
3140 int err = 0;
3141
3142#if defined(DEBUG_SIGNAL)
3143 fprintf(stderr, "do_sigreturn\n");
3144#endif
3145 frame_addr = regs->gregs[15];
3146 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3147 goto badframe;
3148
3149 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
3150 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3151 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
3152 }
3153
3154 if (err)
3155 goto badframe;
3156
3157 target_to_host_sigset_internal(&blocked, &target_set);
3158 sigprocmask(SIG_SETMASK, &blocked, NULL);
3159
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003160 if (restore_sigcontext(regs, &frame->sc, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003161 goto badframe;
3162
3163 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003164 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003165
3166badframe:
3167 unlock_user_struct(frame, frame_addr, 0);
3168 force_sig(TARGET_SIGSEGV);
3169 return 0;
3170}
3171
Andreas Färber05390242012-02-25 03:37:53 +01003172long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003173{
3174 struct target_rt_sigframe *frame;
3175 abi_ulong frame_addr;
3176 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003177 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003178
3179#if defined(DEBUG_SIGNAL)
3180 fprintf(stderr, "do_rt_sigreturn\n");
3181#endif
3182 frame_addr = regs->gregs[15];
3183 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3184 goto badframe;
3185
Aurelien Jarno60e99242010-03-29 02:12:51 +02003186 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
thsc3b5bc82007-12-02 06:31:25 +00003187 sigprocmask(SIG_SETMASK, &blocked, NULL);
3188
Aurelien Jarno60e99242010-03-29 02:12:51 +02003189 if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003190 goto badframe;
3191
3192 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003193 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003194 0, get_sp_from_cpustate(regs)) == -EFAULT)
3195 goto badframe;
3196
3197 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003198 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003199
3200badframe:
3201 unlock_user_struct(frame, frame_addr, 0);
3202 force_sig(TARGET_SIGSEGV);
3203 return 0;
3204}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003205#elif defined(TARGET_MICROBLAZE)
3206
3207struct target_sigcontext {
3208 struct target_pt_regs regs; /* needs to be first */
3209 uint32_t oldmask;
3210};
3211
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003212struct target_stack_t {
3213 abi_ulong ss_sp;
3214 int ss_flags;
3215 unsigned int ss_size;
3216};
3217
3218struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003219 abi_ulong tuc_flags;
3220 abi_ulong tuc_link;
3221 struct target_stack_t tuc_stack;
3222 struct target_sigcontext tuc_mcontext;
3223 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003224};
3225
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003226/* Signal frames. */
3227struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003228 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003229 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3230 uint32_t tramp[2];
3231};
3232
3233struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003234 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003235 struct ucontext uc;
3236 uint32_t tramp[2];
3237};
3238
Andreas Färber05390242012-02-25 03:37:53 +01003239static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003240{
3241 __put_user(env->regs[0], &sc->regs.r0);
3242 __put_user(env->regs[1], &sc->regs.r1);
3243 __put_user(env->regs[2], &sc->regs.r2);
3244 __put_user(env->regs[3], &sc->regs.r3);
3245 __put_user(env->regs[4], &sc->regs.r4);
3246 __put_user(env->regs[5], &sc->regs.r5);
3247 __put_user(env->regs[6], &sc->regs.r6);
3248 __put_user(env->regs[7], &sc->regs.r7);
3249 __put_user(env->regs[8], &sc->regs.r8);
3250 __put_user(env->regs[9], &sc->regs.r9);
3251 __put_user(env->regs[10], &sc->regs.r10);
3252 __put_user(env->regs[11], &sc->regs.r11);
3253 __put_user(env->regs[12], &sc->regs.r12);
3254 __put_user(env->regs[13], &sc->regs.r13);
3255 __put_user(env->regs[14], &sc->regs.r14);
3256 __put_user(env->regs[15], &sc->regs.r15);
3257 __put_user(env->regs[16], &sc->regs.r16);
3258 __put_user(env->regs[17], &sc->regs.r17);
3259 __put_user(env->regs[18], &sc->regs.r18);
3260 __put_user(env->regs[19], &sc->regs.r19);
3261 __put_user(env->regs[20], &sc->regs.r20);
3262 __put_user(env->regs[21], &sc->regs.r21);
3263 __put_user(env->regs[22], &sc->regs.r22);
3264 __put_user(env->regs[23], &sc->regs.r23);
3265 __put_user(env->regs[24], &sc->regs.r24);
3266 __put_user(env->regs[25], &sc->regs.r25);
3267 __put_user(env->regs[26], &sc->regs.r26);
3268 __put_user(env->regs[27], &sc->regs.r27);
3269 __put_user(env->regs[28], &sc->regs.r28);
3270 __put_user(env->regs[29], &sc->regs.r29);
3271 __put_user(env->regs[30], &sc->regs.r30);
3272 __put_user(env->regs[31], &sc->regs.r31);
3273 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3274}
3275
Andreas Färber05390242012-02-25 03:37:53 +01003276static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003277{
3278 __get_user(env->regs[0], &sc->regs.r0);
3279 __get_user(env->regs[1], &sc->regs.r1);
3280 __get_user(env->regs[2], &sc->regs.r2);
3281 __get_user(env->regs[3], &sc->regs.r3);
3282 __get_user(env->regs[4], &sc->regs.r4);
3283 __get_user(env->regs[5], &sc->regs.r5);
3284 __get_user(env->regs[6], &sc->regs.r6);
3285 __get_user(env->regs[7], &sc->regs.r7);
3286 __get_user(env->regs[8], &sc->regs.r8);
3287 __get_user(env->regs[9], &sc->regs.r9);
3288 __get_user(env->regs[10], &sc->regs.r10);
3289 __get_user(env->regs[11], &sc->regs.r11);
3290 __get_user(env->regs[12], &sc->regs.r12);
3291 __get_user(env->regs[13], &sc->regs.r13);
3292 __get_user(env->regs[14], &sc->regs.r14);
3293 __get_user(env->regs[15], &sc->regs.r15);
3294 __get_user(env->regs[16], &sc->regs.r16);
3295 __get_user(env->regs[17], &sc->regs.r17);
3296 __get_user(env->regs[18], &sc->regs.r18);
3297 __get_user(env->regs[19], &sc->regs.r19);
3298 __get_user(env->regs[20], &sc->regs.r20);
3299 __get_user(env->regs[21], &sc->regs.r21);
3300 __get_user(env->regs[22], &sc->regs.r22);
3301 __get_user(env->regs[23], &sc->regs.r23);
3302 __get_user(env->regs[24], &sc->regs.r24);
3303 __get_user(env->regs[25], &sc->regs.r25);
3304 __get_user(env->regs[26], &sc->regs.r26);
3305 __get_user(env->regs[27], &sc->regs.r27);
3306 __get_user(env->regs[28], &sc->regs.r28);
3307 __get_user(env->regs[29], &sc->regs.r29);
3308 __get_user(env->regs[30], &sc->regs.r30);
3309 __get_user(env->regs[31], &sc->regs.r31);
3310 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3311}
3312
3313static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003314 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003315{
3316 abi_ulong sp = env->regs[1];
3317
3318 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3319 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3320
3321 return ((sp - frame_size) & -8UL);
3322}
3323
3324static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003325 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003326{
3327 struct target_signal_frame *frame;
3328 abi_ulong frame_addr;
3329 int err = 0;
3330 int i;
3331
3332 frame_addr = get_sigframe(ka, env, sizeof *frame);
3333 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3334 goto badframe;
3335
3336 /* Save the mask. */
Richard Hendersonf711df62010-11-22 14:57:52 -08003337 err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003338 if (err)
3339 goto badframe;
3340
3341 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3342 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3343 goto badframe;
3344 }
3345
Richard Hendersonf711df62010-11-22 14:57:52 -08003346 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003347
3348 /* Set up to return from userspace. If provided, use a stub
3349 already in userspace. */
3350 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3351 if (ka->sa_flags & TARGET_SA_RESTORER) {
3352 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3353 } else {
3354 uint32_t t;
3355 /* Note, these encodings are _big endian_! */
3356 /* addi r12, r0, __NR_sigreturn */
3357 t = 0x31800000UL | TARGET_NR_sigreturn;
3358 err |= __put_user(t, frame->tramp + 0);
3359 /* brki r14, 0x8 */
3360 t = 0xb9cc0008UL;
3361 err |= __put_user(t, frame->tramp + 1);
3362
3363 /* Return from sighandler will jump to the tramp.
3364 Negative 8 offset because return is rtsd r15, 8 */
3365 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3366 }
3367
3368 if (err)
3369 goto badframe;
3370
3371 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003372 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003373 /* Signal handler args: */
3374 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003375 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003376 /* arg 1: sigcontext */
3377 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003378
3379 /* Offset of 4 to handle microblaze rtid r14, 0 */
3380 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3381
3382 unlock_user_struct(frame, frame_addr, 1);
3383 return;
3384 badframe:
3385 unlock_user_struct(frame, frame_addr, 1);
3386 force_sig(TARGET_SIGSEGV);
3387}
3388
3389static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003390 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003391 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003392{
3393 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3394}
3395
Andreas Färber05390242012-02-25 03:37:53 +01003396long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003397{
3398 struct target_signal_frame *frame;
3399 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003400 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003401 sigset_t set;
3402 int i;
3403
3404 frame_addr = env->regs[R_SP];
3405 /* Make sure the guest isn't playing games. */
3406 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3407 goto badframe;
3408
3409 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003410 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003411 goto badframe;
3412 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3413 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3414 goto badframe;
3415 }
3416 target_to_host_sigset_internal(&set, &target_set);
3417 sigprocmask(SIG_SETMASK, &set, NULL);
3418
Richard Hendersonf711df62010-11-22 14:57:52 -08003419 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003420 /* We got here through a sigreturn syscall, our path back is via an
3421 rtb insn so setup r14 for that. */
3422 env->regs[14] = env->sregs[SR_PC];
3423
3424 unlock_user_struct(frame, frame_addr, 0);
3425 return env->regs[10];
3426 badframe:
3427 unlock_user_struct(frame, frame_addr, 0);
3428 force_sig(TARGET_SIGSEGV);
3429}
3430
Andreas Färber05390242012-02-25 03:37:53 +01003431long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003432{
3433 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3434 return -TARGET_ENOSYS;
3435}
3436
edgar_iglb6d3abd2008-02-28 11:29:27 +00003437#elif defined(TARGET_CRIS)
3438
3439struct target_sigcontext {
3440 struct target_pt_regs regs; /* needs to be first */
3441 uint32_t oldmask;
3442 uint32_t usp; /* usp before stacking this gunk on it */
3443};
3444
3445/* Signal frames. */
3446struct target_signal_frame {
3447 struct target_sigcontext sc;
3448 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3449 uint8_t retcode[8]; /* Trampoline code. */
3450};
3451
3452struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003453 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003454 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003455 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003456 struct ucontext uc;
3457 uint8_t retcode[8]; /* Trampoline code. */
3458};
3459
Andreas Färber05390242012-02-25 03:37:53 +01003460static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003461{
edgar_igl9664d922008-03-03 22:23:53 +00003462 __put_user(env->regs[0], &sc->regs.r0);
3463 __put_user(env->regs[1], &sc->regs.r1);
3464 __put_user(env->regs[2], &sc->regs.r2);
3465 __put_user(env->regs[3], &sc->regs.r3);
3466 __put_user(env->regs[4], &sc->regs.r4);
3467 __put_user(env->regs[5], &sc->regs.r5);
3468 __put_user(env->regs[6], &sc->regs.r6);
3469 __put_user(env->regs[7], &sc->regs.r7);
3470 __put_user(env->regs[8], &sc->regs.r8);
3471 __put_user(env->regs[9], &sc->regs.r9);
3472 __put_user(env->regs[10], &sc->regs.r10);
3473 __put_user(env->regs[11], &sc->regs.r11);
3474 __put_user(env->regs[12], &sc->regs.r12);
3475 __put_user(env->regs[13], &sc->regs.r13);
3476 __put_user(env->regs[14], &sc->usp);
3477 __put_user(env->regs[15], &sc->regs.acr);
3478 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3479 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3480 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003481}
edgar_igl9664d922008-03-03 22:23:53 +00003482
Andreas Färber05390242012-02-25 03:37:53 +01003483static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003484{
edgar_igl9664d922008-03-03 22:23:53 +00003485 __get_user(env->regs[0], &sc->regs.r0);
3486 __get_user(env->regs[1], &sc->regs.r1);
3487 __get_user(env->regs[2], &sc->regs.r2);
3488 __get_user(env->regs[3], &sc->regs.r3);
3489 __get_user(env->regs[4], &sc->regs.r4);
3490 __get_user(env->regs[5], &sc->regs.r5);
3491 __get_user(env->regs[6], &sc->regs.r6);
3492 __get_user(env->regs[7], &sc->regs.r7);
3493 __get_user(env->regs[8], &sc->regs.r8);
3494 __get_user(env->regs[9], &sc->regs.r9);
3495 __get_user(env->regs[10], &sc->regs.r10);
3496 __get_user(env->regs[11], &sc->regs.r11);
3497 __get_user(env->regs[12], &sc->regs.r12);
3498 __get_user(env->regs[13], &sc->regs.r13);
3499 __get_user(env->regs[14], &sc->usp);
3500 __get_user(env->regs[15], &sc->regs.acr);
3501 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3502 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3503 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003504}
3505
Andreas Färber05390242012-02-25 03:37:53 +01003506static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003507{
edgar_igl9664d922008-03-03 22:23:53 +00003508 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003509 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003510 sp = (env->regs[R_SP] & ~3);
3511 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003512}
3513
pbrook624f7972008-05-31 16:11:38 +00003514static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003515 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003516{
3517 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003518 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003519 int err = 0;
3520 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003521
edgar_igl9664d922008-03-03 22:23:53 +00003522 frame_addr = get_sigframe(env, sizeof *frame);
3523 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003524 goto badframe;
3525
3526 /*
3527 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3528 * use this trampoline anymore but it sets it up for GDB.
3529 * In QEMU, using the trampoline simplifies things a bit so we use it.
3530 *
3531 * This is movu.w __NR_sigreturn, r9; break 13;
3532 */
3533 err |= __put_user(0x9c5f, frame->retcode+0);
3534 err |= __put_user(TARGET_NR_sigreturn,
3535 frame->retcode+2);
3536 err |= __put_user(0xe93d, frame->retcode+4);
3537
3538 /* Save the mask. */
3539 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3540 if (err)
3541 goto badframe;
3542
3543 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3544 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3545 goto badframe;
3546 }
3547
3548 setup_sigcontext(&frame->sc, env);
3549
3550 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003551 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003552 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003553 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003554 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003555 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003556
edgar_igl9664d922008-03-03 22:23:53 +00003557 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003558 return;
3559 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003560 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003561 force_sig(TARGET_SIGSEGV);
3562}
3563
pbrook624f7972008-05-31 16:11:38 +00003564static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003565 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003566 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003567{
3568 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3569}
3570
Andreas Färber05390242012-02-25 03:37:53 +01003571long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003572{
3573 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003574 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003575 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003576 sigset_t set;
3577 int i;
3578
edgar_igl9664d922008-03-03 22:23:53 +00003579 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003580 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003581 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003582 goto badframe;
3583
3584 /* Restore blocked signals */
3585 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3586 goto badframe;
3587 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3588 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3589 goto badframe;
3590 }
3591 target_to_host_sigset_internal(&set, &target_set);
3592 sigprocmask(SIG_SETMASK, &set, NULL);
3593
3594 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003595 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003596 return env->regs[10];
3597 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003598 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003599 force_sig(TARGET_SIGSEGV);
3600}
3601
Andreas Färber05390242012-02-25 03:37:53 +01003602long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003603{
3604 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3605 return -TARGET_ENOSYS;
3606}
thsc3b5bc82007-12-02 06:31:25 +00003607
Jia Liud9627832012-07-20 15:50:52 +08003608#elif defined(TARGET_OPENRISC)
3609
3610struct target_sigcontext {
3611 struct target_pt_regs regs;
3612 abi_ulong oldmask;
3613 abi_ulong usp;
3614};
3615
3616struct target_ucontext {
3617 abi_ulong tuc_flags;
3618 abi_ulong tuc_link;
3619 target_stack_t tuc_stack;
3620 struct target_sigcontext tuc_mcontext;
3621 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3622};
3623
3624struct target_rt_sigframe {
3625 abi_ulong pinfo;
3626 uint64_t puc;
3627 struct target_siginfo info;
3628 struct target_sigcontext sc;
3629 struct target_ucontext uc;
3630 unsigned char retcode[16]; /* trampoline code */
3631};
3632
3633/* This is the asm-generic/ucontext.h version */
3634#if 0
3635static int restore_sigcontext(CPUOpenRISCState *regs,
3636 struct target_sigcontext *sc)
3637{
3638 unsigned int err = 0;
3639 unsigned long old_usp;
3640
3641 /* Alwys make any pending restarted system call return -EINTR */
3642 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3643
3644 /* restore the regs from &sc->regs (same as sc, since regs is first)
3645 * (sc is already checked for VERIFY_READ since the sigframe was
3646 * checked in sys_sigreturn previously)
3647 */
3648
3649 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3650 goto badframe;
3651 }
3652
3653 /* make sure the U-flag is set so user-mode cannot fool us */
3654
3655 regs->sr &= ~SR_SM;
3656
3657 /* restore the old USP as it was before we stacked the sc etc.
3658 * (we cannot just pop the sigcontext since we aligned the sp and
3659 * stuff after pushing it)
3660 */
3661
3662 err |= __get_user(old_usp, &sc->usp);
3663 phx_signal("old_usp 0x%lx", old_usp);
3664
3665 __PHX__ REALLY /* ??? */
3666 wrusp(old_usp);
3667 regs->gpr[1] = old_usp;
3668
3669 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3670 * after this completes, but we don't use that mechanism. maybe we can
3671 * use it now ?
3672 */
3673
3674 return err;
3675
3676badframe:
3677 return 1;
3678}
3679#endif
3680
3681/* Set up a signal frame. */
3682
3683static int setup_sigcontext(struct target_sigcontext *sc,
3684 CPUOpenRISCState *regs,
3685 unsigned long mask)
3686{
3687 int err = 0;
3688 unsigned long usp = regs->gpr[1];
3689
3690 /* copy the regs. they are first in sc so we can use sc directly */
3691
3692 /*err |= copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
3693
3694 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3695 the signal handler. The frametype will be restored to its previous
3696 value in restore_sigcontext. */
3697 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3698
3699 /* then some other stuff */
3700 err |= __put_user(mask, &sc->oldmask);
3701 err |= __put_user(usp, &sc->usp); return err;
3702}
3703
3704static inline unsigned long align_sigframe(unsigned long sp)
3705{
3706 unsigned long i;
3707 i = sp & ~3UL;
3708 return i;
3709}
3710
3711static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3712 CPUOpenRISCState *regs,
3713 size_t frame_size)
3714{
3715 unsigned long sp = regs->gpr[1];
3716 int onsigstack = on_sig_stack(sp);
3717
3718 /* redzone */
3719 /* This is the X/Open sanctioned signal stack switching. */
3720 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3721 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3722 }
3723
3724 sp = align_sigframe(sp - frame_size);
3725
3726 /*
3727 * If we are on the alternate signal stack and would overflow it, don't.
3728 * Return an always-bogus address instead so we will die with SIGSEGV.
3729 */
3730
3731 if (onsigstack && !likely(on_sig_stack(sp))) {
3732 return -1L;
3733 }
3734
3735 return sp;
3736}
3737
3738static void setup_frame(int sig, struct target_sigaction *ka,
3739 target_sigset_t *set, CPUOpenRISCState *env)
3740{
3741 qemu_log("Not implement.\n");
3742}
3743
3744static void setup_rt_frame(int sig, struct target_sigaction *ka,
3745 target_siginfo_t *info,
3746 target_sigset_t *set, CPUOpenRISCState *env)
3747{
3748 int err = 0;
3749 abi_ulong frame_addr;
3750 unsigned long return_ip;
3751 struct target_rt_sigframe *frame;
3752 abi_ulong info_addr, uc_addr;
3753
3754 frame_addr = get_sigframe(ka, env, sizeof *frame);
3755
3756 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3757 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3758 goto give_sigsegv;
3759 }
3760
3761 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
3762 err |= __put_user(info_addr, &frame->pinfo);
3763 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
3764 err |= __put_user(uc_addr, &frame->puc);
3765
3766 if (ka->sa_flags & SA_SIGINFO) {
3767 err |= copy_siginfo_to_user(&frame->info, info);
3768 }
3769 if (err) {
3770 goto give_sigsegv;
3771 }
3772
3773 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
3774 err |= __put_user(0, &frame->uc.tuc_flags);
3775 err |= __put_user(0, &frame->uc.tuc_link);
3776 err |= __put_user(target_sigaltstack_used.ss_sp,
3777 &frame->uc.tuc_stack.ss_sp);
3778 err |= __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3779 err |= __put_user(target_sigaltstack_used.ss_size,
3780 &frame->uc.tuc_stack.ss_size);
3781 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
3782
3783 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3784
3785 if (err) {
3786 goto give_sigsegv;
3787 }
3788
3789 /* trampoline - the desired return ip is the retcode itself */
3790 return_ip = (unsigned long)&frame->retcode;
3791 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
3792 err |= __put_user(0xa960, (short *)(frame->retcode + 0));
3793 err |= __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
3794 err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
3795 err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
3796
3797 if (err) {
3798 goto give_sigsegv;
3799 }
3800
3801 /* TODO what is the current->exec_domain stuff and invmap ? */
3802
3803 /* Set up registers for signal handler */
3804 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
3805 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
3806 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
3807 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
3808 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
3809
3810 /* actually move the usp to reflect the stacked frame */
3811 env->gpr[1] = (unsigned long)frame;
3812
3813 return;
3814
3815give_sigsegv:
3816 unlock_user_struct(frame, frame_addr, 1);
3817 if (sig == TARGET_SIGSEGV) {
3818 ka->_sa_handler = TARGET_SIG_DFL;
3819 }
3820 force_sig(TARGET_SIGSEGV);
3821}
3822
3823long do_sigreturn(CPUOpenRISCState *env)
3824{
3825
3826 qemu_log("do_sigreturn: not implemented\n");
3827 return -TARGET_ENOSYS;
3828}
3829
3830long do_rt_sigreturn(CPUOpenRISCState *env)
3831{
3832 qemu_log("do_rt_sigreturn: not implemented\n");
3833 return -TARGET_ENOSYS;
3834}
3835/* TARGET_OPENRISC */
3836
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003837#elif defined(TARGET_S390X)
3838
3839#define __NUM_GPRS 16
3840#define __NUM_FPRS 16
3841#define __NUM_ACRS 16
3842
3843#define S390_SYSCALL_SIZE 2
3844#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
3845
3846#define _SIGCONTEXT_NSIG 64
3847#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
3848#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
3849#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
3850#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
3851#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
3852
3853typedef struct {
3854 target_psw_t psw;
3855 target_ulong gprs[__NUM_GPRS];
3856 unsigned int acrs[__NUM_ACRS];
3857} target_s390_regs_common;
3858
3859typedef struct {
3860 unsigned int fpc;
3861 double fprs[__NUM_FPRS];
3862} target_s390_fp_regs;
3863
3864typedef struct {
3865 target_s390_regs_common regs;
3866 target_s390_fp_regs fpregs;
3867} target_sigregs;
3868
3869struct target_sigcontext {
3870 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
3871 target_sigregs *sregs;
3872};
3873
3874typedef struct {
3875 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
3876 struct target_sigcontext sc;
3877 target_sigregs sregs;
3878 int signo;
3879 uint8_t retcode[S390_SYSCALL_SIZE];
3880} sigframe;
3881
3882struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01003883 target_ulong tuc_flags;
3884 struct target_ucontext *tuc_link;
3885 target_stack_t tuc_stack;
3886 target_sigregs tuc_mcontext;
3887 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003888};
3889
3890typedef struct {
3891 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
3892 uint8_t retcode[S390_SYSCALL_SIZE];
3893 struct target_siginfo info;
3894 struct target_ucontext uc;
3895} rt_sigframe;
3896
3897static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01003898get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003899{
3900 abi_ulong sp;
3901
3902 /* Default to using normal stack */
3903 sp = env->regs[15];
3904
3905 /* This is the X/Open sanctioned signal stack switching. */
3906 if (ka->sa_flags & TARGET_SA_ONSTACK) {
3907 if (!sas_ss_flags(sp)) {
3908 sp = target_sigaltstack_used.ss_sp +
3909 target_sigaltstack_used.ss_size;
3910 }
3911 }
3912
3913 /* This is the legacy signal stack switching. */
3914 else if (/* FIXME !user_mode(regs) */ 0 &&
3915 !(ka->sa_flags & TARGET_SA_RESTORER) &&
3916 ka->sa_restorer) {
3917 sp = (abi_ulong) ka->sa_restorer;
3918 }
3919
3920 return (sp - frame_size) & -8ul;
3921}
3922
Andreas Färber05390242012-02-25 03:37:53 +01003923static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003924{
3925 int i;
3926 //save_access_regs(current->thread.acrs); FIXME
3927
3928 /* Copy a 'clean' PSW mask to the user to avoid leaking
3929 information about whether PER is currently on. */
3930 __put_user(env->psw.mask, &sregs->regs.psw.mask);
3931 __put_user(env->psw.addr, &sregs->regs.psw.addr);
3932 for (i = 0; i < 16; i++) {
3933 __put_user(env->regs[i], &sregs->regs.gprs[i]);
3934 }
3935 for (i = 0; i < 16; i++) {
3936 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
3937 }
3938 /*
3939 * We have to store the fp registers to current->thread.fp_regs
3940 * to merge them with the emulated registers.
3941 */
3942 //save_fp_regs(&current->thread.fp_regs); FIXME
3943 for (i = 0; i < 16; i++) {
3944 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
3945 }
3946}
3947
3948static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003949 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003950{
3951 sigframe *frame;
3952 abi_ulong frame_addr;
3953
3954 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3955 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
3956 (unsigned long long)frame_addr);
3957 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3958 goto give_sigsegv;
3959 }
3960
3961 qemu_log("%s: 1\n", __FUNCTION__);
3962 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
3963 goto give_sigsegv;
3964 }
3965
3966 save_sigregs(env, &frame->sregs);
3967
3968 __put_user((abi_ulong)(unsigned long)&frame->sregs,
3969 (abi_ulong *)&frame->sc.sregs);
3970
3971 /* Set up to return from userspace. If provided, use a stub
3972 already in userspace. */
3973 if (ka->sa_flags & TARGET_SA_RESTORER) {
3974 env->regs[14] = (unsigned long)
3975 ka->sa_restorer | PSW_ADDR_AMODE;
3976 } else {
3977 env->regs[14] = (unsigned long)
3978 frame->retcode | PSW_ADDR_AMODE;
3979 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
3980 (uint16_t *)(frame->retcode)))
3981 goto give_sigsegv;
3982 }
3983
3984 /* Set up backchain. */
3985 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
3986 goto give_sigsegv;
3987 }
3988
3989 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003990 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003991 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
3992
3993 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003994 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003995
3996 /* We forgot to include these in the sigcontext.
3997 To avoid breaking binary compatibility, they are passed as args. */
3998 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
3999 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4000
4001 /* Place signal number on stack to allow backtrace from handler. */
4002 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4003 goto give_sigsegv;
4004 }
4005 unlock_user_struct(frame, frame_addr, 1);
4006 return;
4007
4008give_sigsegv:
4009 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4010 unlock_user_struct(frame, frame_addr, 1);
4011 force_sig(TARGET_SIGSEGV);
4012}
4013
4014static void setup_rt_frame(int sig, struct target_sigaction *ka,
4015 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004016 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004017{
4018 int i;
4019 rt_sigframe *frame;
4020 abi_ulong frame_addr;
4021
4022 frame_addr = get_sigframe(ka, env, sizeof *frame);
4023 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4024 (unsigned long long)frame_addr);
4025 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4026 goto give_sigsegv;
4027 }
4028
4029 qemu_log("%s: 1\n", __FUNCTION__);
4030 if (copy_siginfo_to_user(&frame->info, info)) {
4031 goto give_sigsegv;
4032 }
4033
4034 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004035 __put_user(0, &frame->uc.tuc_flags);
4036 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4037 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004038 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004039 &frame->uc.tuc_stack.ss_flags);
4040 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4041 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004042 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4043 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004044 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004045 }
4046
4047 /* Set up to return from userspace. If provided, use a stub
4048 already in userspace. */
4049 if (ka->sa_flags & TARGET_SA_RESTORER) {
4050 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4051 } else {
4052 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4053 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4054 (uint16_t *)(frame->retcode))) {
4055 goto give_sigsegv;
4056 }
4057 }
4058
4059 /* Set up backchain. */
4060 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4061 goto give_sigsegv;
4062 }
4063
4064 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004065 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004066 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4067
4068 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004069 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4070 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004071 return;
4072
4073give_sigsegv:
4074 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4075 unlock_user_struct(frame, frame_addr, 1);
4076 force_sig(TARGET_SIGSEGV);
4077}
4078
4079static int
Andreas Färber05390242012-02-25 03:37:53 +01004080restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004081{
4082 int err = 0;
4083 int i;
4084
4085 for (i = 0; i < 16; i++) {
4086 err |= __get_user(env->regs[i], &sc->regs.gprs[i]);
4087 }
4088
4089 err |= __get_user(env->psw.mask, &sc->regs.psw.mask);
4090 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4091 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4092 (unsigned long long)env->psw.addr);
4093 err |= __get_user(env->psw.addr, &sc->regs.psw.addr);
4094 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4095
4096 for (i = 0; i < 16; i++) {
4097 err |= __get_user(env->aregs[i], &sc->regs.acrs[i]);
4098 }
4099 for (i = 0; i < 16; i++) {
4100 err |= __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
4101 }
4102
4103 return err;
4104}
4105
Andreas Färber05390242012-02-25 03:37:53 +01004106long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004107{
4108 sigframe *frame;
4109 abi_ulong frame_addr = env->regs[15];
4110 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4111 (unsigned long long)frame_addr);
4112 target_sigset_t target_set;
4113 sigset_t set;
4114
4115 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4116 goto badframe;
4117 }
4118 if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
4119 goto badframe;
4120 }
4121
4122 target_to_host_sigset_internal(&set, &target_set);
4123 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4124
4125 if (restore_sigregs(env, &frame->sregs)) {
4126 goto badframe;
4127 }
4128
4129 unlock_user_struct(frame, frame_addr, 0);
4130 return env->regs[2];
4131
4132badframe:
4133 unlock_user_struct(frame, frame_addr, 0);
4134 force_sig(TARGET_SIGSEGV);
4135 return 0;
4136}
4137
Andreas Färber05390242012-02-25 03:37:53 +01004138long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004139{
4140 rt_sigframe *frame;
4141 abi_ulong frame_addr = env->regs[15];
4142 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4143 (unsigned long long)frame_addr);
4144 sigset_t set;
4145
4146 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4147 goto badframe;
4148 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004149 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004150
4151 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4152
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004153 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004154 goto badframe;
4155 }
4156
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004157 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004158 get_sp_from_cpustate(env)) == -EFAULT) {
4159 goto badframe;
4160 }
4161 unlock_user_struct(frame, frame_addr, 0);
4162 return env->regs[2];
4163
4164badframe:
4165 unlock_user_struct(frame, frame_addr, 0);
4166 force_sig(TARGET_SIGSEGV);
4167 return 0;
4168}
4169
Nathan Froydbcd49332009-05-12 19:13:18 -07004170#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4171
4172/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4173 the signal handling is different enough that we haven't implemented
4174 support for PPC64 yet. Hence the restriction above.
4175
4176 There are various #if'd blocks for code for TARGET_PPC64. These
4177 blocks should go away so that we can successfully run 32-bit and
4178 64-bit binaries on a QEMU configured for PPC64. */
4179
4180/* Size of dummy stack frame allocated when calling signal handler.
4181 See arch/powerpc/include/asm/ptrace.h. */
4182#if defined(TARGET_PPC64)
4183#define SIGNAL_FRAMESIZE 128
4184#else
4185#define SIGNAL_FRAMESIZE 64
4186#endif
4187
4188/* See arch/powerpc/include/asm/sigcontext.h. */
4189struct target_sigcontext {
4190 target_ulong _unused[4];
4191 int32_t signal;
4192#if defined(TARGET_PPC64)
4193 int32_t pad0;
4194#endif
4195 target_ulong handler;
4196 target_ulong oldmask;
4197 target_ulong regs; /* struct pt_regs __user * */
4198 /* TODO: PPC64 includes extra bits here. */
4199};
4200
4201/* Indices for target_mcontext.mc_gregs, below.
4202 See arch/powerpc/include/asm/ptrace.h for details. */
4203enum {
4204 TARGET_PT_R0 = 0,
4205 TARGET_PT_R1 = 1,
4206 TARGET_PT_R2 = 2,
4207 TARGET_PT_R3 = 3,
4208 TARGET_PT_R4 = 4,
4209 TARGET_PT_R5 = 5,
4210 TARGET_PT_R6 = 6,
4211 TARGET_PT_R7 = 7,
4212 TARGET_PT_R8 = 8,
4213 TARGET_PT_R9 = 9,
4214 TARGET_PT_R10 = 10,
4215 TARGET_PT_R11 = 11,
4216 TARGET_PT_R12 = 12,
4217 TARGET_PT_R13 = 13,
4218 TARGET_PT_R14 = 14,
4219 TARGET_PT_R15 = 15,
4220 TARGET_PT_R16 = 16,
4221 TARGET_PT_R17 = 17,
4222 TARGET_PT_R18 = 18,
4223 TARGET_PT_R19 = 19,
4224 TARGET_PT_R20 = 20,
4225 TARGET_PT_R21 = 21,
4226 TARGET_PT_R22 = 22,
4227 TARGET_PT_R23 = 23,
4228 TARGET_PT_R24 = 24,
4229 TARGET_PT_R25 = 25,
4230 TARGET_PT_R26 = 26,
4231 TARGET_PT_R27 = 27,
4232 TARGET_PT_R28 = 28,
4233 TARGET_PT_R29 = 29,
4234 TARGET_PT_R30 = 30,
4235 TARGET_PT_R31 = 31,
4236 TARGET_PT_NIP = 32,
4237 TARGET_PT_MSR = 33,
4238 TARGET_PT_ORIG_R3 = 34,
4239 TARGET_PT_CTR = 35,
4240 TARGET_PT_LNK = 36,
4241 TARGET_PT_XER = 37,
4242 TARGET_PT_CCR = 38,
4243 /* Yes, there are two registers with #39. One is 64-bit only. */
4244 TARGET_PT_MQ = 39,
4245 TARGET_PT_SOFTE = 39,
4246 TARGET_PT_TRAP = 40,
4247 TARGET_PT_DAR = 41,
4248 TARGET_PT_DSISR = 42,
4249 TARGET_PT_RESULT = 43,
4250 TARGET_PT_REGS_COUNT = 44
4251};
4252
4253/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4254 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4255struct target_mcontext {
4256 target_ulong mc_gregs[48];
4257 /* Includes fpscr. */
4258 uint64_t mc_fregs[33];
4259 target_ulong mc_pad[2];
4260 /* We need to handle Altivec and SPE at the same time, which no
4261 kernel needs to do. Fortunately, the kernel defines this bit to
4262 be Altivec-register-large all the time, rather than trying to
4263 twiddle it based on the specific platform. */
4264 union {
4265 /* SPE vector registers. One extra for SPEFSCR. */
4266 uint32_t spe[33];
4267 /* Altivec vector registers. The packing of VSCR and VRSAVE
4268 varies depending on whether we're PPC64 or not: PPC64 splits
4269 them apart; PPC32 stuffs them together. */
4270#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004271#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004272#else
malc3efa9a62009-07-18 13:10:12 +04004273#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004274#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004275 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004276#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004277 } mc_vregs __attribute__((__aligned__(16)));
4278};
4279
4280struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004281 target_ulong tuc_flags;
4282 target_ulong tuc_link; /* struct ucontext __user * */
4283 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004284#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004285 int32_t tuc_pad[7];
4286 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004287 points to uc_mcontext field */
4288#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004289 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004290#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004291 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004292 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004293#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004294 int32_t tuc_maskext[30];
4295 int32_t tuc_pad2[3];
4296 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004297#endif
4298};
4299
4300/* See arch/powerpc/kernel/signal_32.c. */
4301struct target_sigframe {
4302 struct target_sigcontext sctx;
4303 struct target_mcontext mctx;
4304 int32_t abigap[56];
4305};
4306
4307struct target_rt_sigframe {
4308 struct target_siginfo info;
4309 struct target_ucontext uc;
4310 int32_t abigap[56];
4311};
4312
4313/* We use the mc_pad field for the signal return trampoline. */
4314#define tramp mc_pad
4315
4316/* See arch/powerpc/kernel/signal.c. */
4317static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004318 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004319 int frame_size)
4320{
4321 target_ulong oldsp, newsp;
4322
4323 oldsp = env->gpr[1];
4324
4325 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004326 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004327 oldsp = (target_sigaltstack_used.ss_sp
4328 + target_sigaltstack_used.ss_size);
4329 }
4330
4331 newsp = (oldsp - frame_size) & ~0xFUL;
4332
4333 return newsp;
4334}
4335
Andreas Färber05390242012-02-25 03:37:53 +01004336static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004337 int sigret)
4338{
4339 target_ulong msr = env->msr;
4340 int i;
4341 target_ulong ccr = 0;
4342
4343 /* In general, the kernel attempts to be intelligent about what it
4344 needs to save for Altivec/FP/SPE registers. We don't care that
4345 much, so we just go ahead and save everything. */
4346
4347 /* Save general registers. */
4348 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4349 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4350 return 1;
4351 }
4352 }
4353 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4354 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4355 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4356 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4357 return 1;
4358
4359 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4360 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4361 }
4362 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4363 return 1;
4364
4365 /* Save Altivec registers if necessary. */
4366 if (env->insns_flags & PPC_ALTIVEC) {
4367 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004368 ppc_avr_t *avr = &env->avr[i];
4369 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004370
4371 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4372 __put_user(avr->u64[1], &vreg->u64[1])) {
4373 return 1;
4374 }
4375 }
4376 /* Set MSR_VR in the saved MSR value to indicate that
4377 frame->mc_vregs contains valid data. */
4378 msr |= MSR_VR;
4379 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4380 &frame->mc_vregs.altivec[32].u32[3]))
4381 return 1;
4382 }
4383
4384 /* Save floating point registers. */
4385 if (env->insns_flags & PPC_FLOAT) {
4386 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4387 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4388 return 1;
4389 }
4390 }
4391 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4392 return 1;
4393 }
4394
4395 /* Save SPE registers. The kernel only saves the high half. */
4396 if (env->insns_flags & PPC_SPE) {
4397#if defined(TARGET_PPC64)
4398 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4399 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4400 return 1;
4401 }
4402 }
4403#else
4404 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4405 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4406 return 1;
4407 }
4408 }
4409#endif
4410 /* Set MSR_SPE in the saved MSR value to indicate that
4411 frame->mc_vregs contains valid data. */
4412 msr |= MSR_SPE;
4413 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4414 return 1;
4415 }
4416
4417 /* Store MSR. */
4418 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4419 return 1;
4420
4421 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4422 if (sigret) {
4423 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4424 __put_user(0x44000002UL, &frame->tramp[1])) {
4425 return 1;
4426 }
4427 }
4428
4429 return 0;
4430}
4431
Andreas Färber05390242012-02-25 03:37:53 +01004432static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004433 struct target_mcontext *frame, int sig)
4434{
4435 target_ulong save_r2 = 0;
4436 target_ulong msr;
4437 target_ulong ccr;
4438
4439 int i;
4440
4441 if (!sig) {
4442 save_r2 = env->gpr[2];
4443 }
4444
4445 /* Restore general registers. */
4446 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4447 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4448 return 1;
4449 }
4450 }
4451 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4452 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4453 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4454 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4455 return 1;
4456 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4457 return 1;
4458
4459 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4460 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4461 }
4462
4463 if (!sig) {
4464 env->gpr[2] = save_r2;
4465 }
4466 /* Restore MSR. */
4467 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4468 return 1;
4469
4470 /* If doing signal return, restore the previous little-endian mode. */
4471 if (sig)
4472 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4473
4474 /* Restore Altivec registers if necessary. */
4475 if (env->insns_flags & PPC_ALTIVEC) {
4476 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004477 ppc_avr_t *avr = &env->avr[i];
4478 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004479
4480 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4481 __get_user(avr->u64[1], &vreg->u64[1])) {
4482 return 1;
4483 }
4484 }
4485 /* Set MSR_VEC in the saved MSR value to indicate that
4486 frame->mc_vregs contains valid data. */
4487 if (__get_user(env->spr[SPR_VRSAVE],
4488 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4489 return 1;
4490 }
4491
4492 /* Restore floating point registers. */
4493 if (env->insns_flags & PPC_FLOAT) {
4494 uint64_t fpscr;
4495 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4496 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4497 return 1;
4498 }
4499 }
4500 if (__get_user(fpscr, &frame->mc_fregs[32]))
4501 return 1;
4502 env->fpscr = (uint32_t) fpscr;
4503 }
4504
4505 /* Save SPE registers. The kernel only saves the high half. */
4506 if (env->insns_flags & PPC_SPE) {
4507#if defined(TARGET_PPC64)
4508 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4509 uint32_t hi;
4510
4511 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4512 return 1;
4513 }
4514 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4515 }
4516#else
4517 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4518 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4519 return 1;
4520 }
4521 }
4522#endif
4523 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4524 return 1;
4525 }
4526
4527 return 0;
4528}
4529
4530static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004531 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004532{
4533 struct target_sigframe *frame;
4534 struct target_sigcontext *sc;
4535 target_ulong frame_addr, newsp;
4536 int err = 0;
4537 int signal;
4538
4539 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4540 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4541 goto sigsegv;
4542 sc = &frame->sctx;
4543
4544 signal = current_exec_domain_sig(sig);
4545
Samuel Seaybeb526b2013-01-02 10:53:46 +00004546 err |= __put_user(ka->_sa_handler, &sc->handler);
Nathan Froydbcd49332009-05-12 19:13:18 -07004547 err |= __put_user(set->sig[0], &sc->oldmask);
4548#if defined(TARGET_PPC64)
4549 err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
4550#else
4551 err |= __put_user(set->sig[1], &sc->_unused[3]);
4552#endif
4553 err |= __put_user(h2g(&frame->mctx), &sc->regs);
4554 err |= __put_user(sig, &sc->signal);
4555
4556 /* Save user regs. */
4557 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4558
4559 /* The kernel checks for the presence of a VDSO here. We don't
4560 emulate a vdso, so use a sigreturn system call. */
4561 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4562
4563 /* Turn off all fp exceptions. */
4564 env->fpscr = 0;
4565
4566 /* Create a stack frame for the caller of the handler. */
4567 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004568 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004569
4570 if (err)
4571 goto sigsegv;
4572
4573 /* Set up registers for signal handler. */
4574 env->gpr[1] = newsp;
4575 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004576 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004577 env->nip = (target_ulong) ka->_sa_handler;
4578 /* Signal handlers are entered in big-endian mode. */
4579 env->msr &= ~MSR_LE;
4580
4581 unlock_user_struct(frame, frame_addr, 1);
4582 return;
4583
4584sigsegv:
4585 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004586 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004587 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004588}
4589
4590static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004591 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004592 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004593{
4594 struct target_rt_sigframe *rt_sf;
4595 struct target_mcontext *frame;
4596 target_ulong rt_sf_addr, newsp = 0;
4597 int i, err = 0;
4598 int signal;
4599
4600 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4601 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4602 goto sigsegv;
4603
4604 signal = current_exec_domain_sig(sig);
4605
4606 err |= copy_siginfo_to_user(&rt_sf->info, info);
4607
Aurelien Jarno60e99242010-03-29 02:12:51 +02004608 err |= __put_user(0, &rt_sf->uc.tuc_flags);
4609 err |= __put_user(0, &rt_sf->uc.tuc_link);
Nathan Froydbcd49332009-05-12 19:13:18 -07004610 err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004611 &rt_sf->uc.tuc_stack.ss_sp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004612 err |= __put_user(sas_ss_flags(env->gpr[1]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02004613 &rt_sf->uc.tuc_stack.ss_flags);
Nathan Froydbcd49332009-05-12 19:13:18 -07004614 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004615 &rt_sf->uc.tuc_stack.ss_size);
4616 err |= __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4617 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004618 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004619 err |= __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004620 }
4621
Aurelien Jarno60e99242010-03-29 02:12:51 +02004622 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004623 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4624
4625 /* The kernel checks for the presence of a VDSO here. We don't
4626 emulate a vdso, so use a sigreturn system call. */
4627 env->lr = (target_ulong) h2g(frame->tramp);
4628
4629 /* Turn off all fp exceptions. */
4630 env->fpscr = 0;
4631
4632 /* Create a stack frame for the caller of the handler. */
4633 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
4634 err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
4635
4636 if (err)
4637 goto sigsegv;
4638
4639 /* Set up registers for signal handler. */
4640 env->gpr[1] = newsp;
4641 env->gpr[3] = (target_ulong) signal;
4642 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4643 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4644 env->gpr[6] = (target_ulong) h2g(rt_sf);
4645 env->nip = (target_ulong) ka->_sa_handler;
4646 /* Signal handlers are entered in big-endian mode. */
4647 env->msr &= ~MSR_LE;
4648
4649 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4650 return;
4651
4652sigsegv:
4653 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004654 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004655 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004656
4657}
4658
Andreas Färber05390242012-02-25 03:37:53 +01004659long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004660{
4661 struct target_sigcontext *sc = NULL;
4662 struct target_mcontext *sr = NULL;
4663 target_ulong sr_addr, sc_addr;
4664 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004665 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004666
4667 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4668 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4669 goto sigsegv;
4670
4671#if defined(TARGET_PPC64)
4672 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4673#else
4674 if(__get_user(set.sig[0], &sc->oldmask) ||
4675 __get_user(set.sig[1], &sc->_unused[3]))
4676 goto sigsegv;
4677#endif
4678 target_to_host_sigset_internal(&blocked, &set);
4679 sigprocmask(SIG_SETMASK, &blocked, NULL);
4680
4681 if (__get_user(sr_addr, &sc->regs))
4682 goto sigsegv;
4683 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4684 goto sigsegv;
4685 if (restore_user_regs(env, sr, 1))
4686 goto sigsegv;
4687
4688 unlock_user_struct(sr, sr_addr, 1);
4689 unlock_user_struct(sc, sc_addr, 1);
4690 return -TARGET_QEMU_ESIGRETURN;
4691
4692sigsegv:
4693 unlock_user_struct(sr, sr_addr, 1);
4694 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004695 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004696 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004697 return 0;
4698}
4699
4700/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004701static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004702{
4703 struct target_mcontext *mcp;
4704 target_ulong mcp_addr;
4705 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004706 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004707
Aurelien Jarno60e99242010-03-29 02:12:51 +02004708 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004709 sizeof (set)))
4710 return 1;
4711
4712#if defined(TARGET_PPC64)
4713 fprintf (stderr, "do_setcontext: not implemented\n");
4714 return 0;
4715#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004716 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004717 return 1;
4718
4719 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4720 return 1;
4721
4722 target_to_host_sigset_internal(&blocked, &set);
4723 sigprocmask(SIG_SETMASK, &blocked, NULL);
4724 if (restore_user_regs(env, mcp, sig))
4725 goto sigsegv;
4726
4727 unlock_user_struct(mcp, mcp_addr, 1);
4728 return 0;
4729
4730sigsegv:
4731 unlock_user_struct(mcp, mcp_addr, 1);
4732 return 1;
4733#endif
4734}
4735
Andreas Färber05390242012-02-25 03:37:53 +01004736long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004737{
4738 struct target_rt_sigframe *rt_sf = NULL;
4739 target_ulong rt_sf_addr;
4740
4741 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4742 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4743 goto sigsegv;
4744
4745 if (do_setcontext(&rt_sf->uc, env, 1))
4746 goto sigsegv;
4747
4748 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004749 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004750 0, env->gpr[1]);
4751
4752 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4753 return -TARGET_QEMU_ESIGRETURN;
4754
4755sigsegv:
4756 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004757 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004758 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004759 return 0;
4760}
4761
Laurent Vivier492a8742009-08-03 16:12:17 +02004762#elif defined(TARGET_M68K)
4763
4764struct target_sigcontext {
4765 abi_ulong sc_mask;
4766 abi_ulong sc_usp;
4767 abi_ulong sc_d0;
4768 abi_ulong sc_d1;
4769 abi_ulong sc_a0;
4770 abi_ulong sc_a1;
4771 unsigned short sc_sr;
4772 abi_ulong sc_pc;
4773};
4774
4775struct target_sigframe
4776{
4777 abi_ulong pretcode;
4778 int sig;
4779 int code;
4780 abi_ulong psc;
4781 char retcode[8];
4782 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4783 struct target_sigcontext sc;
4784};
Laurent Vivier71811552009-08-03 16:12:18 +02004785
Anthony Liguoric227f092009-10-01 16:12:16 -05004786typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004787#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004788typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004789
4790typedef struct target_fpregset {
4791 int f_fpcntl[3];
4792 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05004793} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004794
4795struct target_mcontext {
4796 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05004797 target_gregset_t gregs;
4798 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004799};
4800
4801#define TARGET_MCONTEXT_VERSION 2
4802
4803struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004804 abi_ulong tuc_flags;
4805 abi_ulong tuc_link;
4806 target_stack_t tuc_stack;
4807 struct target_mcontext tuc_mcontext;
4808 abi_long tuc_filler[80];
4809 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02004810};
4811
4812struct target_rt_sigframe
4813{
4814 abi_ulong pretcode;
4815 int sig;
4816 abi_ulong pinfo;
4817 abi_ulong puc;
4818 char retcode[8];
4819 struct target_siginfo info;
4820 struct target_ucontext uc;
4821};
Laurent Vivier492a8742009-08-03 16:12:17 +02004822
4823static int
Andreas Färber05390242012-02-25 03:37:53 +01004824setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
4825 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02004826{
4827 int err = 0;
4828
4829 err |= __put_user(mask, &sc->sc_mask);
4830 err |= __put_user(env->aregs[7], &sc->sc_usp);
4831 err |= __put_user(env->dregs[0], &sc->sc_d0);
4832 err |= __put_user(env->dregs[1], &sc->sc_d1);
4833 err |= __put_user(env->aregs[0], &sc->sc_a0);
4834 err |= __put_user(env->aregs[1], &sc->sc_a1);
4835 err |= __put_user(env->sr, &sc->sc_sr);
4836 err |= __put_user(env->pc, &sc->sc_pc);
4837
4838 return err;
4839}
4840
4841static int
Andreas Färber05390242012-02-25 03:37:53 +01004842restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02004843{
4844 int err = 0;
4845 int temp;
4846
4847 err |= __get_user(env->aregs[7], &sc->sc_usp);
4848 err |= __get_user(env->dregs[1], &sc->sc_d1);
4849 err |= __get_user(env->aregs[0], &sc->sc_a0);
4850 err |= __get_user(env->aregs[1], &sc->sc_a1);
4851 err |= __get_user(env->pc, &sc->sc_pc);
4852 err |= __get_user(temp, &sc->sc_sr);
4853 env->sr = (env->sr & 0xff00) | (temp & 0xff);
4854
4855 *pd0 = tswapl(sc->sc_d0);
4856
4857 return err;
4858}
4859
4860/*
4861 * Determine which stack to use..
4862 */
4863static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004864get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
4865 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02004866{
4867 unsigned long sp;
4868
4869 sp = regs->aregs[7];
4870
4871 /* This is the X/Open sanctioned signal stack switching. */
4872 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
4873 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
4874 }
4875
4876 return ((sp - frame_size) & -8UL);
4877}
4878
4879static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004880 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02004881{
4882 struct target_sigframe *frame;
4883 abi_ulong frame_addr;
4884 abi_ulong retcode_addr;
4885 abi_ulong sc_addr;
4886 int err = 0;
4887 int i;
4888
4889 frame_addr = get_sigframe(ka, env, sizeof *frame);
4890 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
4891 goto give_sigsegv;
4892
4893 err |= __put_user(sig, &frame->sig);
4894
4895 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
4896 err |= __put_user(sc_addr, &frame->psc);
4897
4898 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
4899 if (err)
4900 goto give_sigsegv;
4901
4902 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
4903 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
4904 goto give_sigsegv;
4905 }
4906
4907 /* Set up to return from userspace. */
4908
4909 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
4910 err |= __put_user(retcode_addr, &frame->pretcode);
4911
4912 /* moveq #,d0; trap #0 */
4913
4914 err |= __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
4915 (long *)(frame->retcode));
4916
4917 if (err)
4918 goto give_sigsegv;
4919
4920 /* Set up to return from userspace */
4921
4922 env->aregs[7] = frame_addr;
4923 env->pc = ka->_sa_handler;
4924
4925 unlock_user_struct(frame, frame_addr, 1);
4926 return;
4927
4928give_sigsegv:
4929 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004930 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02004931}
4932
Laurent Vivier71811552009-08-03 16:12:18 +02004933static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01004934 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02004935{
Aurelien Jarno60e99242010-03-29 02:12:51 +02004936 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004937 int err;
4938
Aurelien Jarno60e99242010-03-29 02:12:51 +02004939 err = __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02004940 err |= __put_user(env->dregs[0], &gregs[0]);
4941 err |= __put_user(env->dregs[1], &gregs[1]);
4942 err |= __put_user(env->dregs[2], &gregs[2]);
4943 err |= __put_user(env->dregs[3], &gregs[3]);
4944 err |= __put_user(env->dregs[4], &gregs[4]);
4945 err |= __put_user(env->dregs[5], &gregs[5]);
4946 err |= __put_user(env->dregs[6], &gregs[6]);
4947 err |= __put_user(env->dregs[7], &gregs[7]);
4948 err |= __put_user(env->aregs[0], &gregs[8]);
4949 err |= __put_user(env->aregs[1], &gregs[9]);
4950 err |= __put_user(env->aregs[2], &gregs[10]);
4951 err |= __put_user(env->aregs[3], &gregs[11]);
4952 err |= __put_user(env->aregs[4], &gregs[12]);
4953 err |= __put_user(env->aregs[5], &gregs[13]);
4954 err |= __put_user(env->aregs[6], &gregs[14]);
4955 err |= __put_user(env->aregs[7], &gregs[15]);
4956 err |= __put_user(env->pc, &gregs[16]);
4957 err |= __put_user(env->sr, &gregs[17]);
4958
4959 return err;
4960}
4961
Andreas Färber05390242012-02-25 03:37:53 +01004962static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02004963 struct target_ucontext *uc,
4964 int *pd0)
4965{
4966 int temp;
4967 int err;
Aurelien Jarno60e99242010-03-29 02:12:51 +02004968 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004969
Aurelien Jarno60e99242010-03-29 02:12:51 +02004970 err = __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02004971 if (temp != TARGET_MCONTEXT_VERSION)
4972 goto badframe;
4973
4974 /* restore passed registers */
4975 err |= __get_user(env->dregs[0], &gregs[0]);
4976 err |= __get_user(env->dregs[1], &gregs[1]);
4977 err |= __get_user(env->dregs[2], &gregs[2]);
4978 err |= __get_user(env->dregs[3], &gregs[3]);
4979 err |= __get_user(env->dregs[4], &gregs[4]);
4980 err |= __get_user(env->dregs[5], &gregs[5]);
4981 err |= __get_user(env->dregs[6], &gregs[6]);
4982 err |= __get_user(env->dregs[7], &gregs[7]);
4983 err |= __get_user(env->aregs[0], &gregs[8]);
4984 err |= __get_user(env->aregs[1], &gregs[9]);
4985 err |= __get_user(env->aregs[2], &gregs[10]);
4986 err |= __get_user(env->aregs[3], &gregs[11]);
4987 err |= __get_user(env->aregs[4], &gregs[12]);
4988 err |= __get_user(env->aregs[5], &gregs[13]);
4989 err |= __get_user(env->aregs[6], &gregs[14]);
4990 err |= __get_user(env->aregs[7], &gregs[15]);
4991 err |= __get_user(env->pc, &gregs[16]);
4992 err |= __get_user(temp, &gregs[17]);
4993 env->sr = (env->sr & 0xff00) | (temp & 0xff);
4994
4995 *pd0 = env->dregs[0];
4996 return err;
4997
4998badframe:
4999 return 1;
5000}
5001
Laurent Vivier492a8742009-08-03 16:12:17 +02005002static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005003 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005004 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005005{
Laurent Vivier71811552009-08-03 16:12:18 +02005006 struct target_rt_sigframe *frame;
5007 abi_ulong frame_addr;
5008 abi_ulong retcode_addr;
5009 abi_ulong info_addr;
5010 abi_ulong uc_addr;
5011 int err = 0;
5012 int i;
5013
5014 frame_addr = get_sigframe(ka, env, sizeof *frame);
5015 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5016 goto give_sigsegv;
5017
5018 err |= __put_user(sig, &frame->sig);
5019
5020 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
5021 err |= __put_user(info_addr, &frame->pinfo);
5022
5023 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
5024 err |= __put_user(uc_addr, &frame->puc);
5025
5026 err |= copy_siginfo_to_user(&frame->info, info);
5027
5028 /* Create the ucontext */
5029
Aurelien Jarno60e99242010-03-29 02:12:51 +02005030 err |= __put_user(0, &frame->uc.tuc_flags);
5031 err |= __put_user(0, &frame->uc.tuc_link);
Laurent Vivier71811552009-08-03 16:12:18 +02005032 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005033 &frame->uc.tuc_stack.ss_sp);
Laurent Vivier71811552009-08-03 16:12:18 +02005034 err |= __put_user(sas_ss_flags(env->aregs[7]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005035 &frame->uc.tuc_stack.ss_flags);
Laurent Vivier71811552009-08-03 16:12:18 +02005036 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005037 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005038 err |= target_rt_setup_ucontext(&frame->uc, env);
5039
5040 if (err)
5041 goto give_sigsegv;
5042
5043 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005044 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005045 goto give_sigsegv;
5046 }
5047
5048 /* Set up to return from userspace. */
5049
5050 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5051 err |= __put_user(retcode_addr, &frame->pretcode);
5052
5053 /* moveq #,d0; notb d0; trap #0 */
5054
5055 err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5056 (long *)(frame->retcode + 0));
5057 err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
5058
5059 if (err)
5060 goto give_sigsegv;
5061
5062 /* Set up to return from userspace */
5063
5064 env->aregs[7] = frame_addr;
5065 env->pc = ka->_sa_handler;
5066
5067 unlock_user_struct(frame, frame_addr, 1);
5068 return;
5069
5070give_sigsegv:
5071 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005072 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005073}
5074
Andreas Färber05390242012-02-25 03:37:53 +01005075long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005076{
5077 struct target_sigframe *frame;
5078 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005079 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005080 sigset_t set;
5081 int d0, i;
5082
5083 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5084 goto badframe;
5085
5086 /* set blocked signals */
5087
5088 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
5089 goto badframe;
5090
5091 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5092 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
5093 goto badframe;
5094 }
5095
5096 target_to_host_sigset_internal(&set, &target_set);
5097 sigprocmask(SIG_SETMASK, &set, NULL);
5098
5099 /* restore registers */
5100
5101 if (restore_sigcontext(env, &frame->sc, &d0))
5102 goto badframe;
5103
5104 unlock_user_struct(frame, frame_addr, 0);
5105 return d0;
5106
5107badframe:
5108 unlock_user_struct(frame, frame_addr, 0);
5109 force_sig(TARGET_SIGSEGV);
5110 return 0;
5111}
5112
Andreas Färber05390242012-02-25 03:37:53 +01005113long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005114{
Laurent Vivier71811552009-08-03 16:12:18 +02005115 struct target_rt_sigframe *frame;
5116 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005117 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005118 sigset_t set;
5119 int d0;
5120
5121 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5122 goto badframe;
5123
5124 target_to_host_sigset_internal(&set, &target_set);
5125 sigprocmask(SIG_SETMASK, &set, NULL);
5126
5127 /* restore registers */
5128
5129 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5130 goto badframe;
5131
5132 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005133 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005134 0, get_sp_from_cpustate(env)) == -EFAULT)
5135 goto badframe;
5136
5137 unlock_user_struct(frame, frame_addr, 0);
5138 return d0;
5139
5140badframe:
5141 unlock_user_struct(frame, frame_addr, 0);
5142 force_sig(TARGET_SIGSEGV);
5143 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005144}
5145
Richard Henderson6049f4f2009-12-27 18:30:03 -08005146#elif defined(TARGET_ALPHA)
5147
5148struct target_sigcontext {
5149 abi_long sc_onstack;
5150 abi_long sc_mask;
5151 abi_long sc_pc;
5152 abi_long sc_ps;
5153 abi_long sc_regs[32];
5154 abi_long sc_ownedfp;
5155 abi_long sc_fpregs[32];
5156 abi_ulong sc_fpcr;
5157 abi_ulong sc_fp_control;
5158 abi_ulong sc_reserved1;
5159 abi_ulong sc_reserved2;
5160 abi_ulong sc_ssize;
5161 abi_ulong sc_sbase;
5162 abi_ulong sc_traparg_a0;
5163 abi_ulong sc_traparg_a1;
5164 abi_ulong sc_traparg_a2;
5165 abi_ulong sc_fp_trap_pc;
5166 abi_ulong sc_fp_trigger_sum;
5167 abi_ulong sc_fp_trigger_inst;
5168};
5169
5170struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005171 abi_ulong tuc_flags;
5172 abi_ulong tuc_link;
5173 abi_ulong tuc_osf_sigmask;
5174 target_stack_t tuc_stack;
5175 struct target_sigcontext tuc_mcontext;
5176 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005177};
5178
5179struct target_sigframe {
5180 struct target_sigcontext sc;
5181 unsigned int retcode[3];
5182};
5183
5184struct target_rt_sigframe {
5185 target_siginfo_t info;
5186 struct target_ucontext uc;
5187 unsigned int retcode[3];
5188};
5189
5190#define INSN_MOV_R30_R16 0x47fe0410
5191#define INSN_LDI_R0 0x201f0000
5192#define INSN_CALLSYS 0x00000083
5193
Andreas Färber05390242012-02-25 03:37:53 +01005194static int setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005195 abi_ulong frame_addr, target_sigset_t *set)
5196{
5197 int i, err = 0;
5198
5199 err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5200 err |= __put_user(set->sig[0], &sc->sc_mask);
5201 err |= __put_user(env->pc, &sc->sc_pc);
5202 err |= __put_user(8, &sc->sc_ps);
5203
5204 for (i = 0; i < 31; ++i) {
5205 err |= __put_user(env->ir[i], &sc->sc_regs[i]);
5206 }
5207 err |= __put_user(0, &sc->sc_regs[31]);
5208
5209 for (i = 0; i < 31; ++i) {
5210 err |= __put_user(env->fir[i], &sc->sc_fpregs[i]);
5211 }
5212 err |= __put_user(0, &sc->sc_fpregs[31]);
5213 err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
5214
5215 err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5216 err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5217 err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */
5218
5219 return err;
5220}
5221
Andreas Färber05390242012-02-25 03:37:53 +01005222static int restore_sigcontext(CPUAlphaState *env,
5223 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005224{
5225 uint64_t fpcr;
5226 int i, err = 0;
5227
5228 err |= __get_user(env->pc, &sc->sc_pc);
5229
5230 for (i = 0; i < 31; ++i) {
5231 err |= __get_user(env->ir[i], &sc->sc_regs[i]);
5232 }
5233 for (i = 0; i < 31; ++i) {
5234 err |= __get_user(env->fir[i], &sc->sc_fpregs[i]);
5235 }
5236
5237 err |= __get_user(fpcr, &sc->sc_fpcr);
5238 cpu_alpha_store_fpcr(env, fpcr);
5239
5240 return err;
5241}
5242
5243static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005244 CPUAlphaState *env,
5245 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005246{
5247 abi_ulong sp = env->ir[IR_SP];
5248
5249 /* This is the X/Open sanctioned signal stack switching. */
5250 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5251 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5252 }
5253 return (sp - framesize) & -32;
5254}
5255
5256static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005257 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005258{
5259 abi_ulong frame_addr, r26;
5260 struct target_sigframe *frame;
5261 int err = 0;
5262
5263 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5264 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5265 goto give_sigsegv;
5266 }
5267
5268 err |= setup_sigcontext(&frame->sc, env, frame_addr, set);
5269
5270 if (ka->sa_restorer) {
5271 r26 = ka->sa_restorer;
5272 } else {
5273 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5274 err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5275 &frame->retcode[1]);
5276 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5277 /* imb() */
5278 r26 = frame_addr;
5279 }
5280
5281 unlock_user_struct(frame, frame_addr, 1);
5282
5283 if (err) {
5284 give_sigsegv:
5285 if (sig == TARGET_SIGSEGV) {
5286 ka->_sa_handler = TARGET_SIG_DFL;
5287 }
5288 force_sig(TARGET_SIGSEGV);
5289 }
5290
5291 env->ir[IR_RA] = r26;
5292 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5293 env->ir[IR_A0] = sig;
5294 env->ir[IR_A1] = 0;
5295 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5296 env->ir[IR_SP] = frame_addr;
5297}
5298
5299static void setup_rt_frame(int sig, struct target_sigaction *ka,
5300 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005301 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005302{
5303 abi_ulong frame_addr, r26;
5304 struct target_rt_sigframe *frame;
5305 int i, err = 0;
5306
5307 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5308 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5309 goto give_sigsegv;
5310 }
5311
5312 err |= copy_siginfo_to_user(&frame->info, info);
5313
Aurelien Jarno60e99242010-03-29 02:12:51 +02005314 err |= __put_user(0, &frame->uc.tuc_flags);
5315 err |= __put_user(0, &frame->uc.tuc_link);
5316 err |= __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005317 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005318 &frame->uc.tuc_stack.ss_sp);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005319 err |= __put_user(sas_ss_flags(env->ir[IR_SP]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005320 &frame->uc.tuc_stack.ss_flags);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005321 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005322 &frame->uc.tuc_stack.ss_size);
5323 err |= setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005324 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005325 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005326 }
5327
5328 if (ka->sa_restorer) {
5329 r26 = ka->sa_restorer;
5330 } else {
5331 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5332 err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5333 &frame->retcode[1]);
5334 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5335 /* imb(); */
5336 r26 = frame_addr;
5337 }
5338
5339 if (err) {
5340 give_sigsegv:
5341 if (sig == TARGET_SIGSEGV) {
5342 ka->_sa_handler = TARGET_SIG_DFL;
5343 }
5344 force_sig(TARGET_SIGSEGV);
5345 }
5346
5347 env->ir[IR_RA] = r26;
5348 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5349 env->ir[IR_A0] = sig;
5350 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5351 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5352 env->ir[IR_SP] = frame_addr;
5353}
5354
Andreas Färber05390242012-02-25 03:37:53 +01005355long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005356{
5357 struct target_sigcontext *sc;
5358 abi_ulong sc_addr = env->ir[IR_A0];
5359 target_sigset_t target_set;
5360 sigset_t set;
5361
5362 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5363 goto badframe;
5364 }
5365
5366 target_sigemptyset(&target_set);
5367 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
5368 goto badframe;
5369 }
5370
5371 target_to_host_sigset_internal(&set, &target_set);
5372 sigprocmask(SIG_SETMASK, &set, NULL);
5373
5374 if (restore_sigcontext(env, sc)) {
5375 goto badframe;
5376 }
5377 unlock_user_struct(sc, sc_addr, 0);
5378 return env->ir[IR_V0];
5379
5380 badframe:
5381 unlock_user_struct(sc, sc_addr, 0);
5382 force_sig(TARGET_SIGSEGV);
5383}
5384
Andreas Färber05390242012-02-25 03:37:53 +01005385long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005386{
5387 abi_ulong frame_addr = env->ir[IR_A0];
5388 struct target_rt_sigframe *frame;
5389 sigset_t set;
5390
5391 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5392 goto badframe;
5393 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005394 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005395 sigprocmask(SIG_SETMASK, &set, NULL);
5396
Aurelien Jarno60e99242010-03-29 02:12:51 +02005397 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005398 goto badframe;
5399 }
5400 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005401 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005402 0, env->ir[IR_SP]) == -EFAULT) {
5403 goto badframe;
5404 }
5405
5406 unlock_user_struct(frame, frame_addr, 0);
5407 return env->ir[IR_V0];
5408
5409
5410 badframe:
5411 unlock_user_struct(frame, frame_addr, 0);
5412 force_sig(TARGET_SIGSEGV);
5413}
5414
bellardb346ff42003-06-15 20:05:50 +00005415#else
5416
pbrook624f7972008-05-31 16:11:38 +00005417static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005418 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005419{
5420 fprintf(stderr, "setup_frame: not implemented\n");
5421}
5422
pbrook624f7972008-05-31 16:11:38 +00005423static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005424 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005425 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005426{
5427 fprintf(stderr, "setup_rt_frame: not implemented\n");
5428}
5429
Andreas Färber9349b4f2012-03-14 01:38:32 +01005430long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005431{
5432 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005433 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005434}
5435
Andreas Färber9349b4f2012-03-14 01:38:32 +01005436long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005437{
5438 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005439 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005440}
5441
bellard66fb9762003-03-23 01:06:05 +00005442#endif
5443
Andreas Färber9349b4f2012-03-14 01:38:32 +01005444void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005445{
5446 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005447 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005448 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005449 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005450 struct emulated_sigtable *k;
5451 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005452 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00005453 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00005454
pbrook624f7972008-05-31 16:11:38 +00005455 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005456 return;
5457
pbrook624f7972008-05-31 16:11:38 +00005458 /* FIXME: This is not threadsafe. */
5459 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005460 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5461 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005462 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005463 k++;
bellard31e31b82003-02-18 22:55:36 +00005464 }
5465 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005466 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005467 return;
bellard66fb9762003-03-23 01:06:05 +00005468
bellard31e31b82003-02-18 22:55:36 +00005469 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005470#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005471 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005472#endif
5473 /* dequeue signal */
5474 q = k->first;
5475 k->first = q->next;
5476 if (!k->first)
5477 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005478
bellard1fddef42005-04-17 19:16:13 +00005479 sig = gdb_handlesig (cpu_env, sig);
5480 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005481 sa = NULL;
5482 handler = TARGET_SIG_IGN;
5483 } else {
5484 sa = &sigact_table[sig - 1];
5485 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005486 }
bellard66fb9762003-03-23 01:06:05 +00005487
bellard66fb9762003-03-23 01:06:05 +00005488 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005489 /* default handler : ignore some signal. The other are job control or fatal */
5490 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5491 kill(getpid(),SIGSTOP);
5492 } else if (sig != TARGET_SIGCHLD &&
5493 sig != TARGET_SIGURG &&
5494 sig != TARGET_SIGWINCH &&
5495 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005496 force_sig(sig);
5497 }
5498 } else if (handler == TARGET_SIG_IGN) {
5499 /* ignore sig */
5500 } else if (handler == TARGET_SIG_ERR) {
5501 force_sig(sig);
5502 } else {
bellard9de5e442003-03-23 16:49:39 +00005503 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005504 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005505 /* SA_NODEFER indicates that the current signal should not be
5506 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005507 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005508 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005509
bellard9de5e442003-03-23 16:49:39 +00005510 /* block signals in the handler using Linux */
5511 sigprocmask(SIG_BLOCK, &set, &old_set);
5512 /* save the previous blocked signal state to restore it at the
5513 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005514 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005515
bellardbc8a22c2003-03-30 21:02:40 +00005516 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005517#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005518 {
5519 CPUX86State *env = cpu_env;
5520 if (env->eflags & VM_MASK)
5521 save_v86_state(env);
5522 }
5523#endif
bellard9de5e442003-03-23 16:49:39 +00005524 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005525#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5526 /* These targets do not have traditional signals. */
5527 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5528#else
pbrook624f7972008-05-31 16:11:38 +00005529 if (sa->sa_flags & TARGET_SA_SIGINFO)
5530 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005531 else
pbrook624f7972008-05-31 16:11:38 +00005532 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005533#endif
pbrook624f7972008-05-31 16:11:38 +00005534 if (sa->sa_flags & TARGET_SA_RESETHAND)
5535 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005536 }
bellard66fb9762003-03-23 01:06:05 +00005537 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005538 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005539}