blob: 29734b2c523e7f80f1ef995c7ef348094fc85c28 [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{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100105 if (sig < 0 || 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{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100112 if (sig < 0 || 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{
Andreas Färbera2247f82013-06-09 19:47:04 +0200391 CPUArchState *env = thread_cpu->env_ptr;
392 TaskState *ts = (TaskState *)env->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300393 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000394 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200395 host_sig = target_to_host_signal(target_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200396 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000397
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300398 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200399 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300400 stop_all_tasks();
401 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200402 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300403 }
404 if (core_dumped) {
405 /* we already dumped the core of target process, we don't want
406 * a coredump of qemu itself */
407 struct rlimit nodump;
408 getrlimit(RLIMIT_CORE, &nodump);
409 nodump.rlim_cur=0;
410 setrlimit(RLIMIT_CORE, &nodump);
411 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200412 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300413 }
414
Stefan Weil0c587512011-04-28 17:20:32 +0200415 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000416 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
417 * a negative value. To get the proper exit code we need to
418 * actually die from an uncaught signal. Here the default signal
419 * handler is installed, we send ourself a signal and we wait for
420 * it to arrive. */
421 sigfillset(&act.sa_mask);
422 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000423 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000424 sigaction(host_sig, &act, NULL);
425
426 /* For some reason raise(host_sig) doesn't send the signal when
427 * statically linked on x86-64. */
428 kill(getpid(), host_sig);
429
430 /* Make sure the signal isn't masked (just reuse the mask inside
431 of act) */
432 sigdelset(&act.sa_mask, host_sig);
433 sigsuspend(&act.sa_mask);
434
435 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000436 abort();
bellard66fb9762003-03-23 01:06:05 +0000437}
438
bellard9de5e442003-03-23 16:49:39 +0000439/* queue a signal so that it will be send to the virtual CPU as soon
440 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100441int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000442{
pbrook624f7972008-05-31 16:11:38 +0000443 TaskState *ts = env->opaque;
444 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000445 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000446 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000447 int queue;
bellard66fb9762003-03-23 01:06:05 +0000448
bellard9de5e442003-03-23 16:49:39 +0000449#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000450 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000451 sig);
bellard66fb9762003-03-23 01:06:05 +0000452#endif
pbrook624f7972008-05-31 16:11:38 +0000453 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000454 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000455 handler = sigact_table[sig - 1]._sa_handler;
aurel32ca587a82008-12-18 22:44:13 +0000456 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000457 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
458 kill(getpid(),SIGSTOP);
459 return 0;
460 } else
bellard66fb9762003-03-23 01:06:05 +0000461 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000462 if (sig != TARGET_SIGCHLD &&
463 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000464 sig != TARGET_SIGWINCH &&
465 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000466 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000467 } else {
468 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000469 }
aurel32ca587a82008-12-18 22:44:13 +0000470 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000471 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000472 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000473 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000474 force_sig(sig);
475 } else {
bellard9de5e442003-03-23 16:49:39 +0000476 pq = &k->first;
477 if (sig < TARGET_SIGRTMIN) {
478 /* if non real time signal, we queue exactly one signal */
479 if (!k->pending)
480 q = &k->info;
481 else
482 return 0;
483 } else {
484 if (!k->pending) {
485 /* first signal */
486 q = &k->info;
487 } else {
pbrook624f7972008-05-31 16:11:38 +0000488 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000489 if (!q)
490 return -EAGAIN;
491 while (*pq != NULL)
492 pq = &(*pq)->next;
493 }
494 }
495 *pq = q;
496 q->info = *info;
497 q->next = NULL;
498 k->pending = 1;
499 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000500 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000501 return 1; /* indicates that the signal was queued */
502 }
503}
504
ths5fafdf22007-09-16 21:08:06 +0000505static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000506 void *puc)
507{
Andreas Färbera2247f82013-06-09 19:47:04 +0200508 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000509 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500510 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000511
512 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000513 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000514 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000515 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000516 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000517 return;
518 }
519
520 /* get target signal number */
521 sig = host_to_target_signal(host_signum);
522 if (sig < 1 || sig > TARGET_NSIG)
523 return;
524#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000525 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000526#endif
527 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200528 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000529 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200530 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000531 }
bellard31e31b82003-02-18 22:55:36 +0000532}
533
ths0da46a62007-10-20 20:23:07 +0000534/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000535/* compare linux/kernel/signal.c:do_sigaltstack() */
536abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000537{
538 int ret;
539 struct target_sigaltstack oss;
540
541 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000542 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000543 {
544 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
545 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
546 __put_user(sas_ss_flags(sp), &oss.ss_flags);
547 }
548
bellard579a97f2007-11-11 14:26:47 +0000549 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000550 {
bellard579a97f2007-11-11 14:26:47 +0000551 struct target_sigaltstack *uss;
552 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000553
ths0da46a62007-10-20 20:23:07 +0000554 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000555 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000556 || __get_user(ss.ss_sp, &uss->ss_sp)
557 || __get_user(ss.ss_size, &uss->ss_size)
558 || __get_user(ss.ss_flags, &uss->ss_flags))
559 goto out;
bellard579a97f2007-11-11 14:26:47 +0000560 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000561
ths0da46a62007-10-20 20:23:07 +0000562 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000563 if (on_sig_stack(sp))
564 goto out;
565
ths0da46a62007-10-20 20:23:07 +0000566 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000567 if (ss.ss_flags != TARGET_SS_DISABLE
568 && ss.ss_flags != TARGET_SS_ONSTACK
569 && ss.ss_flags != 0)
570 goto out;
571
572 if (ss.ss_flags == TARGET_SS_DISABLE) {
573 ss.ss_size = 0;
574 ss.ss_sp = 0;
575 } else {
ths0da46a62007-10-20 20:23:07 +0000576 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000577 if (ss.ss_size < MINSIGSTKSZ)
578 goto out;
579 }
580
581 target_sigaltstack_used.ss_sp = ss.ss_sp;
582 target_sigaltstack_used.ss_size = ss.ss_size;
583 }
584
bellard579a97f2007-11-11 14:26:47 +0000585 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000586 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000587 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000588 goto out;
thsa04e1342007-09-27 13:57:58 +0000589 }
590
591 ret = 0;
592out:
593 return ret;
594}
595
ths0da46a62007-10-20 20:23:07 +0000596/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000597int do_sigaction(int sig, const struct target_sigaction *act,
598 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000599{
pbrook624f7972008-05-31 16:11:38 +0000600 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000601 struct sigaction act1;
602 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000603 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000604
ths2a913eb2008-11-27 15:46:25 +0000605 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000606 return -EINVAL;
607 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000608#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000609 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
610 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000611#endif
612 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800613 __put_user(k->_sa_handler, &oact->_sa_handler);
614 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000615#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800616 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000617#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800618 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000619 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000620 }
621 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000622 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800623 __get_user(k->_sa_handler, &act->_sa_handler);
624 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000625#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800626 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000627#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800628 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000629 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000630
631 /* we update the host linux signal state */
632 host_sig = target_to_host_signal(sig);
633 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
634 sigfillset(&act1.sa_mask);
635 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000636 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000637 act1.sa_flags |= SA_RESTART;
638 /* NOTE: it is important to update the host kernel signal
639 ignore state to avoid getting unexpected interrupted
640 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000641 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000642 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000643 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000644 if (fatal_signal (sig))
645 act1.sa_sigaction = host_signal_handler;
646 else
647 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000648 } else {
649 act1.sa_sigaction = host_signal_handler;
650 }
ths0da46a62007-10-20 20:23:07 +0000651 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000652 }
bellard66fb9762003-03-23 01:06:05 +0000653 }
ths0da46a62007-10-20 20:23:07 +0000654 return ret;
bellard66fb9762003-03-23 01:06:05 +0000655}
bellard31e31b82003-02-18 22:55:36 +0000656
Anthony Liguoric227f092009-10-01 16:12:16 -0500657static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
658 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000659{
660 tswap_siginfo(tinfo, info);
661 return 0;
662}
663
thsc3b5bc82007-12-02 06:31:25 +0000664static inline int current_exec_domain_sig(int sig)
665{
666 return /* current->exec_domain && current->exec_domain->signal_invmap
667 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
668}
669
bellard459a4012007-11-11 19:45:10 +0000670#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000671
672/* from the Linux kernel */
673
674struct target_fpreg {
675 uint16_t significand[4];
676 uint16_t exponent;
677};
678
679struct target_fpxreg {
680 uint16_t significand[4];
681 uint16_t exponent;
682 uint16_t padding[3];
683};
684
685struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000686 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000687};
688
689struct target_fpstate {
690 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000691 abi_ulong cw;
692 abi_ulong sw;
693 abi_ulong tag;
694 abi_ulong ipoff;
695 abi_ulong cssel;
696 abi_ulong dataoff;
697 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000698 struct target_fpreg _st[8];
699 uint16_t status;
700 uint16_t magic; /* 0xffff = regular FPU data only */
701
702 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000703 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
704 abi_ulong mxcsr;
705 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000706 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
707 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000708 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000709};
710
711#define X86_FXSR_MAGIC 0x0000
712
713struct target_sigcontext {
714 uint16_t gs, __gsh;
715 uint16_t fs, __fsh;
716 uint16_t es, __esh;
717 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000718 abi_ulong edi;
719 abi_ulong esi;
720 abi_ulong ebp;
721 abi_ulong esp;
722 abi_ulong ebx;
723 abi_ulong edx;
724 abi_ulong ecx;
725 abi_ulong eax;
726 abi_ulong trapno;
727 abi_ulong err;
728 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000729 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000730 abi_ulong eflags;
731 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000732 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000733 abi_ulong fpstate; /* pointer */
734 abi_ulong oldmask;
735 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000736};
737
bellard66fb9762003-03-23 01:06:05 +0000738struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000739 abi_ulong tuc_flags;
740 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500741 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000742 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500743 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000744};
745
746struct sigframe
747{
blueswir1992f48a2007-10-14 16:27:31 +0000748 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000749 int sig;
750 struct target_sigcontext sc;
751 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000752 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000753 char retcode[8];
754};
755
756struct rt_sigframe
757{
blueswir1992f48a2007-10-14 16:27:31 +0000758 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000759 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000760 abi_ulong pinfo;
761 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000762 struct target_siginfo info;
763 struct target_ucontext uc;
764 struct target_fpstate fpstate;
765 char retcode[8];
766};
767
768/*
769 * Set up a signal frame.
770 */
771
bellard66fb9762003-03-23 01:06:05 +0000772/* XXX: save x87 state */
773static int
774setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000775 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000776{
777 int err = 0;
bellard775b58d2007-11-11 16:22:17 +0000778 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000779
bellard579a97f2007-11-11 14:26:47 +0000780 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000781 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
782 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
783 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
784 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000785 err |= __put_user(env->regs[R_EDI], &sc->edi);
786 err |= __put_user(env->regs[R_ESI], &sc->esi);
787 err |= __put_user(env->regs[R_EBP], &sc->ebp);
788 err |= __put_user(env->regs[R_ESP], &sc->esp);
789 err |= __put_user(env->regs[R_EBX], &sc->ebx);
790 err |= __put_user(env->regs[R_EDX], &sc->edx);
791 err |= __put_user(env->regs[R_ECX], &sc->ecx);
792 err |= __put_user(env->regs[R_EAX], &sc->eax);
bellard66099dd2003-05-08 15:34:02 +0000793 err |= __put_user(env->exception_index, &sc->trapno);
794 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000795 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000796 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000797 err |= __put_user(env->eflags, &sc->eflags);
798 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000799 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000800
bellard28be6232007-11-11 22:23:38 +0000801 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000802 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000803 magic = 0xffff;
804 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000805 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000806
bellard66fb9762003-03-23 01:06:05 +0000807 /* non-iBCS2 extensions.. */
808 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000809 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000810 return err;
811}
812
813/*
814 * Determine which stack to use..
815 */
816
bellard579a97f2007-11-11 14:26:47 +0000817static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000818get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000819{
820 unsigned long esp;
821
822 /* Default to using normal stack */
823 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000824 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000825 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000826 if (sas_ss_flags(esp) == 0)
827 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
828 }
bellard66fb9762003-03-23 01:06:05 +0000829
830 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000831 else
bellarda52c7572003-06-21 13:14:12 +0000832 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000833 !(ka->sa_flags & TARGET_SA_RESTORER) &&
834 ka->sa_restorer) {
835 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000836 }
bellard579a97f2007-11-11 14:26:47 +0000837 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000838}
839
bellard579a97f2007-11-11 14:26:47 +0000840/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000841static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500842 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000843{
bellard579a97f2007-11-11 14:26:47 +0000844 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000845 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000846 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000847
bellard579a97f2007-11-11 14:26:47 +0000848 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000849
bellard579a97f2007-11-11 14:26:47 +0000850 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000851 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000852
thsc3b5bc82007-12-02 06:31:25 +0000853 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000854 &frame->sig);
855 if (err)
856 goto give_sigsegv;
857
bellard28be6232007-11-11 22:23:38 +0000858 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
859 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000860 if (err)
861 goto give_sigsegv;
862
bellard92319442004-06-19 16:58:13 +0000863 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
864 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
865 goto give_sigsegv;
866 }
bellard66fb9762003-03-23 01:06:05 +0000867
868 /* Set up to return from userspace. If provided, use a stub
869 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000870 if (ka->sa_flags & TARGET_SA_RESTORER) {
871 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000872 } else {
bellard775b58d2007-11-11 16:22:17 +0000873 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000874 abi_ulong retcode_addr;
875 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
876 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000877 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000878 val16 = 0xb858;
879 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000880 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000881 val16 = 0x80cd;
882 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000883 }
884
885 if (err)
886 goto give_sigsegv;
887
888 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000889 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000890 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000891
892 cpu_x86_load_seg(env, R_DS, __USER_DS);
893 cpu_x86_load_seg(env, R_ES, __USER_DS);
894 cpu_x86_load_seg(env, R_SS, __USER_DS);
895 cpu_x86_load_seg(env, R_CS, __USER_CS);
896 env->eflags &= ~TF_MASK;
897
bellard579a97f2007-11-11 14:26:47 +0000898 unlock_user_struct(frame, frame_addr, 1);
899
bellard66fb9762003-03-23 01:06:05 +0000900 return;
901
902give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000903 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000904 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000905 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000906 force_sig(TARGET_SIGSEGV /* , current */);
907}
908
bellard579a97f2007-11-11 14:26:47 +0000909/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000910static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500911 target_siginfo_t *info,
912 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000913{
bellard28be6232007-11-11 22:23:38 +0000914 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000915 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000916 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000917
bellard579a97f2007-11-11 14:26:47 +0000918 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000919
bellard579a97f2007-11-11 14:26:47 +0000920 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000921 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000922
thsc3b5bc82007-12-02 06:31:25 +0000923 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000924 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000925 addr = frame_addr + offsetof(struct rt_sigframe, info);
926 err |= __put_user(addr, &frame->pinfo);
927 addr = frame_addr + offsetof(struct rt_sigframe, uc);
928 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000929 err |= copy_siginfo_to_user(&frame->info, info);
930 if (err)
931 goto give_sigsegv;
932
933 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000934 err |= __put_user(0, &frame->uc.tuc_flags);
935 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000936 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000937 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000938 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000939 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000940 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000941 &frame->uc.tuc_stack.ss_size);
942 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000943 env, set->sig[0],
944 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000945 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000946 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000947 goto give_sigsegv;
948 }
bellard66fb9762003-03-23 01:06:05 +0000949
950 /* Set up to return from userspace. If provided, use a stub
951 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000952 if (ka->sa_flags & TARGET_SA_RESTORER) {
953 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000954 } else {
bellard775b58d2007-11-11 16:22:17 +0000955 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000956 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
957 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000958 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000959 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000960 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000961 val16 = 0x80cd;
962 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000963 }
964
965 if (err)
966 goto give_sigsegv;
967
968 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000969 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000970 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000971
972 cpu_x86_load_seg(env, R_DS, __USER_DS);
973 cpu_x86_load_seg(env, R_ES, __USER_DS);
974 cpu_x86_load_seg(env, R_SS, __USER_DS);
975 cpu_x86_load_seg(env, R_CS, __USER_CS);
976 env->eflags &= ~TF_MASK;
977
bellard579a97f2007-11-11 14:26:47 +0000978 unlock_user_struct(frame, frame_addr, 1);
979
bellard66fb9762003-03-23 01:06:05 +0000980 return;
981
982give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000983 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000984 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000985 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000986 force_sig(TARGET_SIGSEGV /* , current */);
987}
988
989static int
990restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
991{
992 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000993 abi_ulong fpstate_addr;
994 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000995
bellard28be6232007-11-11 22:23:38 +0000996 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
997 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
998 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
999 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001000
bellard28be6232007-11-11 22:23:38 +00001001 env->regs[R_EDI] = tswapl(sc->edi);
1002 env->regs[R_ESI] = tswapl(sc->esi);
1003 env->regs[R_EBP] = tswapl(sc->ebp);
1004 env->regs[R_ESP] = tswapl(sc->esp);
1005 env->regs[R_EBX] = tswapl(sc->ebx);
1006 env->regs[R_EDX] = tswapl(sc->edx);
1007 env->regs[R_ECX] = tswapl(sc->ecx);
1008 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001009
Mike McCormack9a826d72011-06-01 15:14:37 +09001010 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1011 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001012
bellard28be6232007-11-11 22:23:38 +00001013 tmpflags = tswapl(sc->eflags);
1014 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1015 // regs->orig_eax = -1; /* disable syscall checks */
1016
1017 fpstate_addr = tswapl(sc->fpstate);
1018 if (fpstate_addr != 0) {
1019 if (!access_ok(VERIFY_READ, fpstate_addr,
1020 sizeof(struct target_fpstate)))
1021 goto badframe;
1022 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001023 }
1024
bellard28be6232007-11-11 22:23:38 +00001025 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001026 return err;
bellard66fb9762003-03-23 01:06:05 +00001027badframe:
1028 return 1;
bellard66fb9762003-03-23 01:06:05 +00001029}
1030
1031long do_sigreturn(CPUX86State *env)
1032{
bellard579a97f2007-11-11 14:26:47 +00001033 struct sigframe *frame;
1034 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001035 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001036 sigset_t set;
1037 int eax, i;
1038
bellard447db212003-05-10 15:10:36 +00001039#if defined(DEBUG_SIGNAL)
1040 fprintf(stderr, "do_sigreturn\n");
1041#endif
bellard579a97f2007-11-11 14:26:47 +00001042 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1043 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001044 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +00001045 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
1046 goto badframe;
1047 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1048 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
1049 goto badframe;
1050 }
bellard66fb9762003-03-23 01:06:05 +00001051
bellard92319442004-06-19 16:58:13 +00001052 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +00001053 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001054
bellard66fb9762003-03-23 01:06:05 +00001055 /* restore registers */
1056 if (restore_sigcontext(env, &frame->sc, &eax))
1057 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001058 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001059 return eax;
1060
1061badframe:
bellard579a97f2007-11-11 14:26:47 +00001062 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001063 force_sig(TARGET_SIGSEGV);
1064 return 0;
1065}
1066
1067long do_rt_sigreturn(CPUX86State *env)
1068{
bellard28be6232007-11-11 22:23:38 +00001069 abi_ulong frame_addr;
1070 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001071 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001072 int eax;
1073
bellard28be6232007-11-11 22:23:38 +00001074 frame_addr = env->regs[R_ESP] - 4;
1075 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1076 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001077 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +00001078 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001079
bellardb8076a72005-04-07 22:20:31 +00001080 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001081 goto badframe;
1082
bellard28be6232007-11-11 22:23:38 +00001083 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1084 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001085 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001086
bellard28be6232007-11-11 22:23:38 +00001087 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001088 return eax;
1089
1090badframe:
bellard28be6232007-11-11 22:23:38 +00001091 unlock_user_struct(frame, frame_addr, 0);
1092 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001093 return 0;
1094}
1095
Andreas Schwab1744aea2013-09-03 20:12:16 +01001096#elif defined(TARGET_AARCH64)
1097
1098struct target_sigcontext {
1099 uint64_t fault_address;
1100 /* AArch64 registers */
1101 uint64_t regs[31];
1102 uint64_t sp;
1103 uint64_t pc;
1104 uint64_t pstate;
1105 /* 4K reserved for FP/SIMD state and future expansion */
1106 char __reserved[4096] __attribute__((__aligned__(16)));
1107};
1108
1109struct target_ucontext {
1110 abi_ulong tuc_flags;
1111 abi_ulong tuc_link;
1112 target_stack_t tuc_stack;
1113 target_sigset_t tuc_sigmask;
1114 /* glibc uses a 1024-bit sigset_t */
1115 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1116 /* last for future expansion */
1117 struct target_sigcontext tuc_mcontext;
1118};
1119
1120/*
1121 * Header to be used at the beginning of structures extending the user
1122 * context. Such structures must be placed after the rt_sigframe on the stack
1123 * and be 16-byte aligned. The last structure must be a dummy one with the
1124 * magic and size set to 0.
1125 */
1126struct target_aarch64_ctx {
1127 uint32_t magic;
1128 uint32_t size;
1129};
1130
1131#define TARGET_FPSIMD_MAGIC 0x46508001
1132
1133struct target_fpsimd_context {
1134 struct target_aarch64_ctx head;
1135 uint32_t fpsr;
1136 uint32_t fpcr;
1137 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1138};
1139
1140/*
1141 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1142 * user space as it will change with the addition of new context. User space
1143 * should check the magic/size information.
1144 */
1145struct target_aux_context {
1146 struct target_fpsimd_context fpsimd;
1147 /* additional context to be added before "end" */
1148 struct target_aarch64_ctx end;
1149};
1150
1151struct target_rt_sigframe {
1152 struct target_siginfo info;
1153 struct target_ucontext uc;
1154 uint64_t fp;
1155 uint64_t lr;
1156 uint32_t tramp[2];
1157};
1158
1159static int target_setup_sigframe(struct target_rt_sigframe *sf,
1160 CPUARMState *env, target_sigset_t *set)
1161{
1162 int i;
1163 struct target_aux_context *aux =
1164 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1165
1166 /* set up the stack frame for unwinding */
1167 __put_user(env->xregs[29], &sf->fp);
1168 __put_user(env->xregs[30], &sf->lr);
1169
1170 for (i = 0; i < 31; i++) {
1171 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1172 }
1173 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1174 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001175 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001176
1177 __put_user(/*current->thread.fault_address*/ 0,
1178 &sf->uc.tuc_mcontext.fault_address);
1179
1180 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1181 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1182 }
1183
1184 for (i = 0; i < 32; i++) {
1185#ifdef TARGET_WORDS_BIGENDIAN
1186 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1187 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1188#else
1189 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1190 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1191#endif
1192 }
Will Newtone0ee1382014-01-04 22:15:48 +00001193 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1194 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001195 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1196 __put_user(sizeof(struct target_fpsimd_context),
1197 &aux->fpsimd.head.size);
1198
1199 /* set the "end" magic */
1200 __put_user(0, &aux->end.magic);
1201 __put_user(0, &aux->end.size);
1202
1203 return 0;
1204}
1205
1206static int target_restore_sigframe(CPUARMState *env,
1207 struct target_rt_sigframe *sf)
1208{
1209 sigset_t set;
1210 int i;
1211 struct target_aux_context *aux =
1212 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001213 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001214 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001215
1216 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
1217 sigprocmask(SIG_SETMASK, &set, NULL);
1218
1219 for (i = 0; i < 31; i++) {
1220 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1221 }
1222
1223 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1224 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001225 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1226 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001227
1228 __get_user(magic, &aux->fpsimd.head.magic);
1229 __get_user(size, &aux->fpsimd.head.size);
1230
1231 if (magic != TARGET_FPSIMD_MAGIC
1232 || size != sizeof(struct target_fpsimd_context)) {
1233 return 1;
1234 }
1235
Peter Maydell4cf23482014-03-02 19:36:38 +00001236 for (i = 0; i < 32; i++) {
1237#ifdef TARGET_WORDS_BIGENDIAN
1238 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1239 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1240#else
1241 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1242 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1243#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001244 }
Will Newtone0ee1382014-01-04 22:15:48 +00001245 __get_user(fpsr, &aux->fpsimd.fpsr);
1246 vfp_set_fpsr(env, fpsr);
1247 __get_user(fpcr, &aux->fpsimd.fpcr);
1248 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001249
1250 return 0;
1251}
1252
1253static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1254{
1255 abi_ulong sp;
1256
1257 sp = env->xregs[31];
1258
1259 /*
1260 * This is the X/Open sanctioned signal stack switching.
1261 */
1262 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1263 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1264 }
1265
1266 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1267
1268 return sp;
1269}
1270
1271static void target_setup_frame(int usig, struct target_sigaction *ka,
1272 target_siginfo_t *info, target_sigset_t *set,
1273 CPUARMState *env)
1274{
1275 struct target_rt_sigframe *frame;
1276 abi_ulong frame_addr;
1277
1278 frame_addr = get_sigframe(ka, env);
1279 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1280 goto give_sigsegv;
1281 }
1282
1283 __put_user(0, &frame->uc.tuc_flags);
1284 __put_user(0, &frame->uc.tuc_link);
1285
1286 __put_user(target_sigaltstack_used.ss_sp,
1287 &frame->uc.tuc_stack.ss_sp);
1288 __put_user(sas_ss_flags(env->xregs[31]),
1289 &frame->uc.tuc_stack.ss_flags);
1290 __put_user(target_sigaltstack_used.ss_size,
1291 &frame->uc.tuc_stack.ss_size);
1292 target_setup_sigframe(frame, env, set);
1293 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1294 __put_user(0xd2801168, &frame->tramp[0]);
1295 __put_user(0xd4000001, &frame->tramp[1]);
1296 env->xregs[0] = usig;
1297 env->xregs[31] = frame_addr;
1298 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1299 env->pc = ka->_sa_handler;
1300 env->xregs[30] = env->xregs[31] +
1301 offsetof(struct target_rt_sigframe, tramp);
1302 if (info) {
1303 if (copy_siginfo_to_user(&frame->info, info)) {
1304 goto give_sigsegv;
1305 }
1306 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1307 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1308 }
1309
1310 unlock_user_struct(frame, frame_addr, 1);
1311 return;
1312
1313 give_sigsegv:
1314 unlock_user_struct(frame, frame_addr, 1);
1315 force_sig(TARGET_SIGSEGV);
1316}
1317
1318static void setup_rt_frame(int sig, struct target_sigaction *ka,
1319 target_siginfo_t *info, target_sigset_t *set,
1320 CPUARMState *env)
1321{
1322 target_setup_frame(sig, ka, info, set, env);
1323}
1324
1325static void setup_frame(int sig, struct target_sigaction *ka,
1326 target_sigset_t *set, CPUARMState *env)
1327{
1328 target_setup_frame(sig, ka, 0, set, env);
1329}
1330
1331long do_rt_sigreturn(CPUARMState *env)
1332{
1333 struct target_rt_sigframe *frame;
1334 abi_ulong frame_addr = env->xregs[31];
1335
1336 if (frame_addr & 15) {
1337 goto badframe;
1338 }
1339
1340 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1341 goto badframe;
1342 }
1343
1344 if (target_restore_sigframe(env, frame)) {
1345 goto badframe;
1346 }
1347
1348 if (do_sigaltstack(frame_addr +
1349 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1350 0, get_sp_from_cpustate(env)) == -EFAULT) {
1351 goto badframe;
1352 }
1353
1354 unlock_user_struct(frame, frame_addr, 0);
1355 return env->xregs[0];
1356
1357 badframe:
1358 unlock_user_struct(frame, frame_addr, 0);
1359 force_sig(TARGET_SIGSEGV);
1360 return 0;
1361}
1362
1363long do_sigreturn(CPUARMState *env)
1364{
1365 return do_rt_sigreturn(env);
1366}
1367
bellard43fff232003-07-09 19:31:39 +00001368#elif defined(TARGET_ARM)
1369
1370struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001371 abi_ulong trap_no;
1372 abi_ulong error_code;
1373 abi_ulong oldmask;
1374 abi_ulong arm_r0;
1375 abi_ulong arm_r1;
1376 abi_ulong arm_r2;
1377 abi_ulong arm_r3;
1378 abi_ulong arm_r4;
1379 abi_ulong arm_r5;
1380 abi_ulong arm_r6;
1381 abi_ulong arm_r7;
1382 abi_ulong arm_r8;
1383 abi_ulong arm_r9;
1384 abi_ulong arm_r10;
1385 abi_ulong arm_fp;
1386 abi_ulong arm_ip;
1387 abi_ulong arm_sp;
1388 abi_ulong arm_lr;
1389 abi_ulong arm_pc;
1390 abi_ulong arm_cpsr;
1391 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001392};
1393
pbrooka745ec62008-05-06 15:36:17 +00001394struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001395 abi_ulong tuc_flags;
1396 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001397 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001398 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001399 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001400};
1401
pbrooka745ec62008-05-06 15:36:17 +00001402struct target_ucontext_v2 {
1403 abi_ulong tuc_flags;
1404 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001405 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001406 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001407 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001408 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001409 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1410};
1411
Peter Maydell0d871bd2010-11-24 15:20:05 +00001412struct target_user_vfp {
1413 uint64_t fpregs[32];
1414 abi_ulong fpscr;
1415};
1416
1417struct target_user_vfp_exc {
1418 abi_ulong fpexc;
1419 abi_ulong fpinst;
1420 abi_ulong fpinst2;
1421};
1422
1423struct target_vfp_sigframe {
1424 abi_ulong magic;
1425 abi_ulong size;
1426 struct target_user_vfp ufp;
1427 struct target_user_vfp_exc ufp_exc;
1428} __attribute__((__aligned__(8)));
1429
Peter Maydell08e11252010-11-24 15:20:07 +00001430struct target_iwmmxt_sigframe {
1431 abi_ulong magic;
1432 abi_ulong size;
1433 uint64_t regs[16];
1434 /* Note that not all the coprocessor control registers are stored here */
1435 uint32_t wcssf;
1436 uint32_t wcasf;
1437 uint32_t wcgr0;
1438 uint32_t wcgr1;
1439 uint32_t wcgr2;
1440 uint32_t wcgr3;
1441} __attribute__((__aligned__(8)));
1442
Peter Maydell0d871bd2010-11-24 15:20:05 +00001443#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001444#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001445
pbrooka8c33202008-05-07 23:22:46 +00001446struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001447{
1448 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001449 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1450 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001451};
1452
pbrooka8c33202008-05-07 23:22:46 +00001453struct sigframe_v2
1454{
1455 struct target_ucontext_v2 uc;
1456 abi_ulong retcode;
1457};
1458
pbrooka745ec62008-05-06 15:36:17 +00001459struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001460{
bellardf8b0aa22007-11-11 23:03:42 +00001461 abi_ulong pinfo;
1462 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001463 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001464 struct target_ucontext_v1 uc;
1465 abi_ulong retcode;
1466};
1467
1468struct rt_sigframe_v2
1469{
1470 struct target_siginfo info;
1471 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001472 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001473};
1474
1475#define TARGET_CONFIG_CPU_32 1
1476
1477/*
1478 * For ARM syscalls, we encode the syscall number into the instruction.
1479 */
1480#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1481#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1482
1483/*
1484 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1485 * need two 16-bit instructions.
1486 */
1487#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1488#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1489
blueswir1992f48a2007-10-14 16:27:31 +00001490static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001491 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1492 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1493};
1494
1495
bellard43fff232003-07-09 19:31:39 +00001496#define __get_user_error(x,p,e) __get_user(x, p)
1497
Andreas Färber05390242012-02-25 03:37:53 +01001498static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001499{
1500 return 1;
1501}
1502
pbrooka8c33202008-05-07 23:22:46 +00001503static void
bellard43fff232003-07-09 19:31:39 +00001504setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001505 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001506{
pbrooka8c33202008-05-07 23:22:46 +00001507 __put_user(env->regs[0], &sc->arm_r0);
1508 __put_user(env->regs[1], &sc->arm_r1);
1509 __put_user(env->regs[2], &sc->arm_r2);
1510 __put_user(env->regs[3], &sc->arm_r3);
1511 __put_user(env->regs[4], &sc->arm_r4);
1512 __put_user(env->regs[5], &sc->arm_r5);
1513 __put_user(env->regs[6], &sc->arm_r6);
1514 __put_user(env->regs[7], &sc->arm_r7);
1515 __put_user(env->regs[8], &sc->arm_r8);
1516 __put_user(env->regs[9], &sc->arm_r9);
1517 __put_user(env->regs[10], &sc->arm_r10);
1518 __put_user(env->regs[11], &sc->arm_fp);
1519 __put_user(env->regs[12], &sc->arm_ip);
1520 __put_user(env->regs[13], &sc->arm_sp);
1521 __put_user(env->regs[14], &sc->arm_lr);
1522 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001523#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001524 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001525#endif
1526
pbrooka8c33202008-05-07 23:22:46 +00001527 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1528 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1529 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1530 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001531}
1532
bellard579a97f2007-11-11 14:26:47 +00001533static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001534get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001535{
1536 unsigned long sp = regs->regs[13];
1537
bellard43fff232003-07-09 19:31:39 +00001538 /*
1539 * This is the X/Open sanctioned signal stack switching.
1540 */
pbrook624f7972008-05-31 16:11:38 +00001541 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001542 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001543 /*
1544 * ATPCS B01 mandates 8-byte alignment
1545 */
bellard579a97f2007-11-11 14:26:47 +00001546 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001547}
1548
1549static int
Andreas Färber05390242012-02-25 03:37:53 +01001550setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001551 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001552{
pbrook624f7972008-05-31 16:11:38 +00001553 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001554 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001555 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001556 uint32_t cpsr = cpsr_read(env);
1557
1558 cpsr &= ~CPSR_IT;
1559 if (thumb) {
1560 cpsr |= CPSR_T;
1561 } else {
1562 cpsr &= ~CPSR_T;
1563 }
bellard43fff232003-07-09 19:31:39 +00001564
pbrook624f7972008-05-31 16:11:38 +00001565 if (ka->sa_flags & TARGET_SA_RESTORER) {
1566 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001567 } else {
1568 unsigned int idx = thumb;
1569
pbrook624f7972008-05-31 16:11:38 +00001570 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001571 idx += 2;
1572
1573 if (__put_user(retcodes[idx], rc))
1574 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001575
bellardf8b0aa22007-11-11 23:03:42 +00001576 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001577 }
1578
1579 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001580 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001581 env->regs[14] = retcode;
1582 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001583 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001584
1585 return 0;
1586}
1587
Andreas Färber05390242012-02-25 03:37:53 +01001588static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001589{
1590 int i;
1591 struct target_vfp_sigframe *vfpframe;
1592 vfpframe = (struct target_vfp_sigframe *)regspace;
1593 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1594 __put_user(sizeof(*vfpframe), &vfpframe->size);
1595 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001596 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001597 }
1598 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1599 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1600 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1601 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1602 return (abi_ulong*)(vfpframe+1);
1603}
1604
Andreas Färber05390242012-02-25 03:37:53 +01001605static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1606 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001607{
1608 int i;
1609 struct target_iwmmxt_sigframe *iwmmxtframe;
1610 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1611 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1612 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1613 for (i = 0; i < 16; i++) {
1614 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1615 }
1616 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1617 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1618 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1619 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1620 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1621 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1622 return (abi_ulong*)(iwmmxtframe+1);
1623}
1624
pbrooka8c33202008-05-07 23:22:46 +00001625static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001626 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001627{
pbrooka8c33202008-05-07 23:22:46 +00001628 struct target_sigaltstack stack;
1629 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001630 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001631
1632 /* Clear all the bits of the ucontext we don't use. */
1633 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1634
1635 memset(&stack, 0, sizeof(stack));
1636 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1637 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1638 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1639 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1640
1641 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001642 /* Save coprocessor signal frame. */
1643 regspace = uc->tuc_regspace;
1644 if (arm_feature(env, ARM_FEATURE_VFP)) {
1645 regspace = setup_sigframe_v2_vfp(regspace, env);
1646 }
Peter Maydell08e11252010-11-24 15:20:07 +00001647 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1648 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1649 }
1650
Peter Maydell0d871bd2010-11-24 15:20:05 +00001651 /* Write terminating magic word */
1652 __put_user(0, regspace);
1653
pbrooka8c33202008-05-07 23:22:46 +00001654 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1655 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1656 }
1657}
1658
1659/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001660static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001661 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001662{
1663 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001664 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001665 int i;
bellard43fff232003-07-09 19:31:39 +00001666
bellard579a97f2007-11-11 14:26:47 +00001667 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1668 return;
1669
pbrooka8c33202008-05-07 23:22:46 +00001670 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001671
bellard92319442004-06-19 16:58:13 +00001672 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1673 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001674 goto end;
bellard43fff232003-07-09 19:31:39 +00001675 }
1676
pbrooka8c33202008-05-07 23:22:46 +00001677 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1678 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001679
1680end:
1681 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001682}
1683
pbrook624f7972008-05-31 16:11:38 +00001684static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001685 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001686{
1687 struct sigframe_v2 *frame;
1688 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1689
1690 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1691 return;
1692
1693 setup_sigframe_v2(&frame->uc, set, regs);
1694
1695 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1696 frame_addr + offsetof(struct sigframe_v2, retcode));
1697
1698 unlock_user_struct(frame, frame_addr, 1);
1699}
1700
pbrook624f7972008-05-31 16:11:38 +00001701static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001702 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001703{
1704 if (get_osversion() >= 0x020612) {
1705 setup_frame_v2(usig, ka, set, regs);
1706 } else {
1707 setup_frame_v1(usig, ka, set, regs);
1708 }
bellard43fff232003-07-09 19:31:39 +00001709}
1710
bellard579a97f2007-11-11 14:26:47 +00001711/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001712static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001713 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001714 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001715{
pbrooka745ec62008-05-06 15:36:17 +00001716 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001717 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001718 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001719 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001720 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001721
bellard579a97f2007-11-11 14:26:47 +00001722 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001723 return /* 1 */;
1724
pbrooka745ec62008-05-06 15:36:17 +00001725 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001726 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001727 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001728 __put_user(uc_addr, &frame->puc);
1729 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001730
1731 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001732 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001733
thsa04e1342007-09-27 13:57:58 +00001734 memset(&stack, 0, sizeof(stack));
1735 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1736 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1737 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001738 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001739
pbrooka8c33202008-05-07 23:22:46 +00001740 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001741 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001742 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001743 goto end;
bellard92319442004-06-19 16:58:13 +00001744 }
bellard43fff232003-07-09 19:31:39 +00001745
pbrooka8c33202008-05-07 23:22:46 +00001746 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1747 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001748
pbrooka8c33202008-05-07 23:22:46 +00001749 env->regs[1] = info_addr;
1750 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001751
1752end:
1753 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001754}
1755
pbrook624f7972008-05-31 16:11:38 +00001756static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001757 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001758 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001759{
1760 struct rt_sigframe_v2 *frame;
1761 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001762 abi_ulong info_addr, uc_addr;
1763
1764 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1765 return /* 1 */;
1766
1767 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1768 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001769 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001770
pbrooka8c33202008-05-07 23:22:46 +00001771 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001772
pbrooka8c33202008-05-07 23:22:46 +00001773 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1774 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001775
pbrooka8c33202008-05-07 23:22:46 +00001776 env->regs[1] = info_addr;
1777 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001778
bellard579a97f2007-11-11 14:26:47 +00001779 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001780}
1781
pbrook624f7972008-05-31 16:11:38 +00001782static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001783 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001784 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001785{
1786 if (get_osversion() >= 0x020612) {
1787 setup_rt_frame_v2(usig, ka, info, set, env);
1788 } else {
1789 setup_rt_frame_v1(usig, ka, info, set, env);
1790 }
1791}
1792
bellard43fff232003-07-09 19:31:39 +00001793static int
Andreas Färber05390242012-02-25 03:37:53 +01001794restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001795{
1796 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001797 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001798
1799 __get_user_error(env->regs[0], &sc->arm_r0, err);
1800 __get_user_error(env->regs[1], &sc->arm_r1, err);
1801 __get_user_error(env->regs[2], &sc->arm_r2, err);
1802 __get_user_error(env->regs[3], &sc->arm_r3, err);
1803 __get_user_error(env->regs[4], &sc->arm_r4, err);
1804 __get_user_error(env->regs[5], &sc->arm_r5, err);
1805 __get_user_error(env->regs[6], &sc->arm_r6, err);
1806 __get_user_error(env->regs[7], &sc->arm_r7, err);
1807 __get_user_error(env->regs[8], &sc->arm_r8, err);
1808 __get_user_error(env->regs[9], &sc->arm_r9, err);
1809 __get_user_error(env->regs[10], &sc->arm_r10, err);
1810 __get_user_error(env->regs[11], &sc->arm_fp, err);
1811 __get_user_error(env->regs[12], &sc->arm_ip, err);
1812 __get_user_error(env->regs[13], &sc->arm_sp, err);
1813 __get_user_error(env->regs[14], &sc->arm_lr, err);
1814 __get_user_error(env->regs[15], &sc->arm_pc, err);
1815#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001816 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001817 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001818#endif
1819
1820 err |= !valid_user_regs(env);
1821
1822 return err;
1823}
1824
Andreas Färber05390242012-02-25 03:37:53 +01001825static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001826{
bellardf8b0aa22007-11-11 23:03:42 +00001827 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001828 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001829 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001830 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001831 int i;
bellard43fff232003-07-09 19:31:39 +00001832
1833 /*
1834 * Since we stacked the signal on a 64-bit boundary,
1835 * then 'sp' should be word aligned here. If it's
1836 * not, then the user is trying to mess with us.
1837 */
bellardf8b0aa22007-11-11 23:03:42 +00001838 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001839 if (frame_addr & 7) {
1840 goto badframe;
1841 }
1842
bellardf8b0aa22007-11-11 23:03:42 +00001843 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1844 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001845
bellard92319442004-06-19 16:58:13 +00001846 if (__get_user(set.sig[0], &frame->sc.oldmask))
1847 goto badframe;
1848 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1849 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1850 goto badframe;
1851 }
bellard43fff232003-07-09 19:31:39 +00001852
bellard92319442004-06-19 16:58:13 +00001853 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001854 sigprocmask(SIG_SETMASK, &host_set, NULL);
1855
1856 if (restore_sigcontext(env, &frame->sc))
1857 goto badframe;
1858
1859#if 0
1860 /* Send SIGTRAP if we're single-stepping */
1861 if (ptrace_cancel_bpt(current))
1862 send_sig(SIGTRAP, current, 1);
1863#endif
bellardf8b0aa22007-11-11 23:03:42 +00001864 unlock_user_struct(frame, frame_addr, 0);
1865 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001866
1867badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001868 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001869 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001870 return 0;
1871}
1872
Andreas Färber05390242012-02-25 03:37:53 +01001873static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001874{
1875 int i;
1876 abi_ulong magic, sz;
1877 uint32_t fpscr, fpexc;
1878 struct target_vfp_sigframe *vfpframe;
1879 vfpframe = (struct target_vfp_sigframe *)regspace;
1880
1881 __get_user(magic, &vfpframe->magic);
1882 __get_user(sz, &vfpframe->size);
1883 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1884 return 0;
1885 }
1886 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001887 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001888 }
1889 __get_user(fpscr, &vfpframe->ufp.fpscr);
1890 vfp_set_fpscr(env, fpscr);
1891 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1892 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1893 * and the exception flag is cleared
1894 */
1895 fpexc |= (1 << 30);
1896 fpexc &= ~((1 << 31) | (1 << 28));
1897 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1898 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1899 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1900 return (abi_ulong*)(vfpframe + 1);
1901}
1902
Andreas Färber05390242012-02-25 03:37:53 +01001903static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1904 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001905{
1906 int i;
1907 abi_ulong magic, sz;
1908 struct target_iwmmxt_sigframe *iwmmxtframe;
1909 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1910
1911 __get_user(magic, &iwmmxtframe->magic);
1912 __get_user(sz, &iwmmxtframe->size);
1913 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1914 return 0;
1915 }
1916 for (i = 0; i < 16; i++) {
1917 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1918 }
1919 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1920 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1921 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1922 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1923 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1924 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1925 return (abi_ulong*)(iwmmxtframe + 1);
1926}
1927
Andreas Färber05390242012-02-25 03:37:53 +01001928static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001929 struct target_ucontext_v2 *uc)
1930{
1931 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001932 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001933
1934 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1935 sigprocmask(SIG_SETMASK, &host_set, NULL);
1936
1937 if (restore_sigcontext(env, &uc->tuc_mcontext))
1938 return 1;
1939
Peter Maydell5f9099d2010-11-24 15:20:06 +00001940 /* Restore coprocessor signal frame */
1941 regspace = uc->tuc_regspace;
1942 if (arm_feature(env, ARM_FEATURE_VFP)) {
1943 regspace = restore_sigframe_v2_vfp(env, regspace);
1944 if (!regspace) {
1945 return 1;
1946 }
1947 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001948 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1949 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1950 if (!regspace) {
1951 return 1;
1952 }
1953 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001954
pbrooka8c33202008-05-07 23:22:46 +00001955 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1956 return 1;
1957
1958#if 0
1959 /* Send SIGTRAP if we're single-stepping */
1960 if (ptrace_cancel_bpt(current))
1961 send_sig(SIGTRAP, current, 1);
1962#endif
1963
1964 return 0;
1965}
1966
Andreas Färber05390242012-02-25 03:37:53 +01001967static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001968{
1969 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001970 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00001971
1972 /*
1973 * Since we stacked the signal on a 64-bit boundary,
1974 * then 'sp' should be word aligned here. If it's
1975 * not, then the user is trying to mess with us.
1976 */
pbrooka8c33202008-05-07 23:22:46 +00001977 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001978 if (frame_addr & 7) {
1979 goto badframe;
1980 }
1981
pbrooka8c33202008-05-07 23:22:46 +00001982 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1983 goto badframe;
1984
1985 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1986 goto badframe;
1987
1988 unlock_user_struct(frame, frame_addr, 0);
1989 return env->regs[0];
1990
1991badframe:
1992 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001993 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00001994 return 0;
1995}
1996
Andreas Färber05390242012-02-25 03:37:53 +01001997long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001998{
1999 if (get_osversion() >= 0x020612) {
2000 return do_sigreturn_v2(env);
2001 } else {
2002 return do_sigreturn_v1(env);
2003 }
2004}
2005
Andreas Färber05390242012-02-25 03:37:53 +01002006static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002007{
bellardf8b0aa22007-11-11 23:03:42 +00002008 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002009 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002010 sigset_t host_set;
2011
2012 /*
2013 * Since we stacked the signal on a 64-bit boundary,
2014 * then 'sp' should be word aligned here. If it's
2015 * not, then the user is trying to mess with us.
2016 */
bellardf8b0aa22007-11-11 23:03:42 +00002017 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002018 if (frame_addr & 7) {
2019 goto badframe;
2020 }
2021
bellardf8b0aa22007-11-11 23:03:42 +00002022 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2023 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002024
bellardb8076a72005-04-07 22:20:31 +00002025 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00002026 sigprocmask(SIG_SETMASK, &host_set, NULL);
2027
bellardb8076a72005-04-07 22:20:31 +00002028 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002029 goto badframe;
2030
pbrooka745ec62008-05-06 15:36:17 +00002031 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 +00002032 goto badframe;
2033
bellard43fff232003-07-09 19:31:39 +00002034#if 0
2035 /* Send SIGTRAP if we're single-stepping */
2036 if (ptrace_cancel_bpt(current))
2037 send_sig(SIGTRAP, current, 1);
2038#endif
bellardf8b0aa22007-11-11 23:03:42 +00002039 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002040 return env->regs[0];
2041
2042badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002043 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002044 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002045 return 0;
2046}
2047
Andreas Färber05390242012-02-25 03:37:53 +01002048static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002049{
2050 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002051 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002052
2053 /*
2054 * Since we stacked the signal on a 64-bit boundary,
2055 * then 'sp' should be word aligned here. If it's
2056 * not, then the user is trying to mess with us.
2057 */
pbrooka745ec62008-05-06 15:36:17 +00002058 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002059 if (frame_addr & 7) {
2060 goto badframe;
2061 }
2062
pbrooka745ec62008-05-06 15:36:17 +00002063 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2064 goto badframe;
2065
pbrooka8c33202008-05-07 23:22:46 +00002066 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2067 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002068
pbrooka745ec62008-05-06 15:36:17 +00002069 unlock_user_struct(frame, frame_addr, 0);
2070 return env->regs[0];
2071
2072badframe:
2073 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002074 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002075 return 0;
2076}
2077
Andreas Färber05390242012-02-25 03:37:53 +01002078long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002079{
2080 if (get_osversion() >= 0x020612) {
2081 return do_rt_sigreturn_v2(env);
2082 } else {
2083 return do_rt_sigreturn_v1(env);
2084 }
2085}
2086
bellard6d5e2162004-09-30 22:04:13 +00002087#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002088
bellard6d5e2162004-09-30 22:04:13 +00002089#define __SUNOS_MAXWIN 31
2090
2091/* This is what SunOS does, so shall I. */
2092struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002093 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002094
blueswir1992f48a2007-10-14 16:27:31 +00002095 abi_ulong sigc_mask; /* sigmask to restore */
2096 abi_ulong sigc_sp; /* stack pointer */
2097 abi_ulong sigc_pc; /* program counter */
2098 abi_ulong sigc_npc; /* next program counter */
2099 abi_ulong sigc_psr; /* for condition codes etc */
2100 abi_ulong sigc_g1; /* User uses these two registers */
2101 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002102
2103 /* Now comes information regarding the users window set
2104 * at the time of the signal.
2105 */
blueswir1992f48a2007-10-14 16:27:31 +00002106 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002107
2108 /* stack ptrs for each regwin buf */
2109 char *sigc_spbuf[__SUNOS_MAXWIN];
2110
2111 /* Windows to restore after signal */
2112 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002113 abi_ulong locals[8];
2114 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002115 } sigc_wbuf[__SUNOS_MAXWIN];
2116};
2117/* A Sparc stack frame */
2118struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002119 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002120 abi_ulong ins[8];
2121 /* It's simpler to treat fp and callers_pc as elements of ins[]
2122 * since we never need to access them ourselves.
2123 */
bellard6d5e2162004-09-30 22:04:13 +00002124 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002125 abi_ulong xargs[6];
2126 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002127};
2128
2129typedef struct {
2130 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002131 abi_ulong psr;
2132 abi_ulong pc;
2133 abi_ulong npc;
2134 abi_ulong y;
2135 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002136 } si_regs;
2137 int si_mask;
2138} __siginfo_t;
2139
2140typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002141 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002142 unsigned long si_fsr;
2143 unsigned long si_fpqdepth;
2144 struct {
2145 unsigned long *insn_addr;
2146 unsigned long insn;
2147 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002148} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002149
2150
2151struct target_signal_frame {
2152 struct sparc_stackf ss;
2153 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002154 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002155 abi_ulong insns[2] __attribute__ ((aligned (8)));
2156 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2157 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002158 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002159};
2160struct target_rt_signal_frame {
2161 struct sparc_stackf ss;
2162 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002163 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002164 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002165 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002166 unsigned int insns[2];
2167 stack_t stack;
2168 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002169 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002170};
2171
bellarde80cfcf2004-12-19 23:18:01 +00002172#define UREG_O0 16
2173#define UREG_O6 22
2174#define UREG_I0 0
2175#define UREG_I1 1
2176#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002177#define UREG_I3 3
2178#define UREG_I4 4
2179#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002180#define UREG_I6 6
2181#define UREG_I7 7
2182#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002183#define UREG_FP UREG_I6
2184#define UREG_SP UREG_O6
2185
pbrook624f7972008-05-31 16:11:38 +00002186static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002187 CPUSPARCState *env,
2188 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002189{
bellard459a4012007-11-11 19:45:10 +00002190 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002191
2192 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002193
2194 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002195 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002196 if (!on_sig_stack(sp)
2197 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2198 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002199 }
bellard459a4012007-11-11 19:45:10 +00002200 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002201}
2202
2203static int
Andreas Färber05390242012-02-25 03:37:53 +01002204setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002205{
2206 int err = 0, i;
2207
bellard6d5e2162004-09-30 22:04:13 +00002208 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00002209 err |= __put_user(env->pc, &si->si_regs.pc);
2210 err |= __put_user(env->npc, &si->si_regs.npc);
2211 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002212 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00002213 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
2214 }
bellarda315a142005-01-30 22:59:18 +00002215 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002216 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002217 }
bellard6d5e2162004-09-30 22:04:13 +00002218 err |= __put_user(mask, &si->si_mask);
2219 return err;
2220}
bellarde80cfcf2004-12-19 23:18:01 +00002221
bellard80a9d032005-01-03 23:31:27 +00002222#if 0
bellard6d5e2162004-09-30 22:04:13 +00002223static int
2224setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002225 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002226{
2227 int err = 0;
2228
2229 err |= __put_user(mask, &sc->sigc_mask);
2230 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2231 err |= __put_user(env->pc, &sc->sigc_pc);
2232 err |= __put_user(env->npc, &sc->sigc_npc);
2233 err |= __put_user(env->psr, &sc->sigc_psr);
2234 err |= __put_user(env->gregs[1], &sc->sigc_g1);
2235 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
2236
2237 return err;
2238}
bellard80a9d032005-01-03 23:31:27 +00002239#endif
bellard6d5e2162004-09-30 22:04:13 +00002240#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2241
pbrook624f7972008-05-31 16:11:38 +00002242static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002243 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002244{
bellard459a4012007-11-11 19:45:10 +00002245 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002246 struct target_signal_frame *sf;
2247 int sigframe_size, err, i;
2248
2249 /* 1. Make sure everything is clean */
2250 //synchronize_user_stack();
2251
2252 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002253 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002254
bellard459a4012007-11-11 19:45:10 +00002255 sf = lock_user(VERIFY_WRITE, sf_addr,
2256 sizeof(struct target_signal_frame), 0);
2257 if (!sf)
2258 goto sigsegv;
2259
bellarde80cfcf2004-12-19 23:18:01 +00002260 //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 +00002261#if 0
2262 if (invalid_frame_pointer(sf, sigframe_size))
2263 goto sigill_and_return;
2264#endif
2265 /* 2. Save the current process state */
2266 err = setup___siginfo(&sf->info, env, set->sig[0]);
2267 err |= __put_user(0, &sf->extra_size);
2268
2269 //err |= save_fpu_state(regs, &sf->fpu_state);
2270 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
2271
2272 err |= __put_user(set->sig[0], &sf->info.si_mask);
2273 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2274 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
2275 }
2276
bellarda315a142005-01-30 22:59:18 +00002277 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002278 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002279 }
bellarda315a142005-01-30 22:59:18 +00002280 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002281 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002282 }
bellard6d5e2162004-09-30 22:04:13 +00002283 if (err)
2284 goto sigsegv;
2285
2286 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002287 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002288 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002289 env->regwptr[UREG_I1] = sf_addr +
2290 offsetof(struct target_signal_frame, info);
2291 env->regwptr[UREG_I2] = sf_addr +
2292 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002293
2294 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002295 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002296 env->npc = (env->pc + 4);
2297 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002298 if (ka->sa_restorer)
2299 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002300 else {
bellard775b58d2007-11-11 16:22:17 +00002301 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002302
2303 env->regwptr[UREG_I7] = sf_addr +
2304 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002305
2306 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002307 val32 = 0x821020d8;
2308 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002309
2310 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002311 val32 = 0x91d02010;
2312 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002313 if (err)
2314 goto sigsegv;
2315
2316 /* Flush instruction space. */
2317 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002318 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002319 }
bellard459a4012007-11-11 19:45:10 +00002320 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002321 return;
bellard459a4012007-11-11 19:45:10 +00002322#if 0
2323sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002324 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002325#endif
bellard6d5e2162004-09-30 22:04:13 +00002326sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002327 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002328 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002329 force_sig(TARGET_SIGSEGV);
2330}
2331static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002332restore_fpu_state(CPUSPARCState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00002333{
2334 int err;
2335#if 0
2336#ifdef CONFIG_SMP
2337 if (current->flags & PF_USEDFPU)
2338 regs->psr &= ~PSR_EF;
2339#else
2340 if (current == last_task_used_math) {
2341 last_task_used_math = 0;
2342 regs->psr &= ~PSR_EF;
2343 }
2344#endif
2345 current->used_math = 1;
2346 current->flags &= ~PF_USEDFPU;
2347#endif
2348#if 0
2349 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
2350 return -EFAULT;
2351#endif
2352
bellardfafffae2006-10-28 12:09:16 +00002353 /* XXX: incorrect */
Blue Swirl8954bae2012-07-30 15:29:11 +00002354 err = copy_from_user(&env->fpr[0], fpu->si_float_regs[0],
2355 (sizeof(abi_ulong) * 32));
bellard6d5e2162004-09-30 22:04:13 +00002356 err |= __get_user(env->fsr, &fpu->si_fsr);
2357#if 0
2358 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
2359 if (current->thread.fpqdepth != 0)
2360 err |= __copy_from_user(&current->thread.fpqueue[0],
2361 &fpu->si_fpqueue[0],
2362 ((sizeof(unsigned long) +
2363 (sizeof(unsigned long *)))*16));
2364#endif
2365 return err;
2366}
2367
2368
pbrook624f7972008-05-31 16:11:38 +00002369static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002370 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002371 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002372{
2373 fprintf(stderr, "setup_rt_frame: not implemented\n");
2374}
2375
Andreas Färber05390242012-02-25 03:37:53 +01002376long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002377{
bellardf8b0aa22007-11-11 23:03:42 +00002378 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002379 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002380 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002381 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002382 sigset_t host_set;
bellarde80cfcf2004-12-19 23:18:01 +00002383 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00002384
bellardf8b0aa22007-11-11 23:03:42 +00002385 sf_addr = env->regwptr[UREG_FP];
2386 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2387 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002388#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002389 fprintf(stderr, "sigreturn\n");
2390 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 +00002391#endif
bellarde80cfcf2004-12-19 23:18:01 +00002392 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002393
2394 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002395
bellardf8b0aa22007-11-11 23:03:42 +00002396 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002397 goto segv_and_exit;
2398
2399 err = __get_user(pc, &sf->info.si_regs.pc);
2400 err |= __get_user(npc, &sf->info.si_regs.npc);
2401
bellard6d5e2162004-09-30 22:04:13 +00002402 if ((pc | npc) & 3)
2403 goto segv_and_exit;
2404
2405 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00002406 err |= __get_user(up_psr, &sf->info.si_regs.psr);
2407
bellard6d5e2162004-09-30 22:04:13 +00002408 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002409 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2410 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2411
2412 env->pc = pc;
2413 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00002414 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002415 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002416 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2417 }
bellarda315a142005-01-30 22:59:18 +00002418 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002419 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2420 }
bellard6d5e2162004-09-30 22:04:13 +00002421
Peter Maydell2aec3a22011-06-16 17:37:14 +01002422 /* FIXME: implement FPU save/restore:
2423 * __get_user(fpu_save, &sf->fpu_save);
2424 * if (fpu_save)
2425 * err |= restore_fpu_state(env, fpu_save);
2426 */
bellard6d5e2162004-09-30 22:04:13 +00002427
2428 /* This is pretty much atomic, no amount locking would prevent
2429 * the races which exist anyways.
2430 */
2431 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002432 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2433 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
2434 }
2435
2436 target_to_host_sigset_internal(&host_set, &set);
2437 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002438
2439 if (err)
2440 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002441 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002442 return env->regwptr[0];
2443
2444segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002445 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002446 force_sig(TARGET_SIGSEGV);
2447}
2448
Andreas Färber05390242012-02-25 03:37:53 +01002449long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002450{
2451 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002452 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002453}
2454
bellard459a4012007-11-11 19:45:10 +00002455#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002456#define MC_TSTATE 0
2457#define MC_PC 1
2458#define MC_NPC 2
2459#define MC_Y 3
2460#define MC_G1 4
2461#define MC_G2 5
2462#define MC_G3 6
2463#define MC_G4 7
2464#define MC_G5 8
2465#define MC_G6 9
2466#define MC_G7 10
2467#define MC_O0 11
2468#define MC_O1 12
2469#define MC_O2 13
2470#define MC_O3 14
2471#define MC_O4 15
2472#define MC_O5 16
2473#define MC_O6 17
2474#define MC_O7 18
2475#define MC_NGREG 19
2476
Anthony Liguoric227f092009-10-01 16:12:16 -05002477typedef abi_ulong target_mc_greg_t;
2478typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002479
2480struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002481 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002482 uint32_t mcfq_insn;
2483};
2484
2485struct target_mc_fpu {
2486 union {
2487 uint32_t sregs[32];
2488 uint64_t dregs[32];
2489 //uint128_t qregs[16];
2490 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002491 abi_ulong mcfpu_fsr;
2492 abi_ulong mcfpu_fprs;
2493 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002494 struct target_mc_fq *mcfpu_fq;
2495 unsigned char mcfpu_qcnt;
2496 unsigned char mcfpu_qentsz;
2497 unsigned char mcfpu_enab;
2498};
Anthony Liguoric227f092009-10-01 16:12:16 -05002499typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002500
2501typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002502 target_mc_gregset_t mc_gregs;
2503 target_mc_greg_t mc_fp;
2504 target_mc_greg_t mc_i7;
2505 target_mc_fpu_t mc_fpregs;
2506} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002507
2508struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002509 struct target_ucontext *tuc_link;
2510 abi_ulong tuc_flags;
2511 target_sigset_t tuc_sigmask;
2512 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002513};
2514
2515/* A V9 register window */
2516struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002517 abi_ulong locals[8];
2518 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002519};
2520
2521#define TARGET_STACK_BIAS 2047
2522
2523/* {set, get}context() needed for 64-bit SparcLinux userland. */
2524void sparc64_set_context(CPUSPARCState *env)
2525{
bellard459a4012007-11-11 19:45:10 +00002526 abi_ulong ucp_addr;
2527 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002528 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002529 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002530 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002531 int err;
2532 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002533
bellard459a4012007-11-11 19:45:10 +00002534 ucp_addr = env->regwptr[UREG_I0];
2535 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2536 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002537 grp = &ucp->tuc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002538 err = __get_user(pc, &((*grp)[MC_PC]));
2539 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002540 if (err || ((pc | npc) & 3))
2541 goto do_sigsegv;
2542 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002543 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002544 sigset_t set;
2545
2546 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002547 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002548 goto do_sigsegv;
2549 } else {
bellard459a4012007-11-11 19:45:10 +00002550 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002551 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002552 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002553 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002554 err |= __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002555 }
blueswir15bfb56b2007-10-05 17:01:51 +00002556 if (err)
2557 goto do_sigsegv;
2558 }
2559 target_to_host_sigset_internal(&set, &target_set);
2560 sigprocmask(SIG_SETMASK, &set, NULL);
2561 }
2562 env->pc = pc;
2563 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002564 err |= __get_user(env->y, &((*grp)[MC_Y]));
2565 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002566 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002567 cpu_put_ccr(env, tstate >> 32);
2568 cpu_put_cwp64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002569 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2570 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2571 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2572 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2573 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2574 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2575 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2576 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2577 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2578 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2579 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2580 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2581 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2582 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2583 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002584
Aurelien Jarno60e99242010-03-29 02:12:51 +02002585 err |= __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2586 err |= __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002587
bellard459a4012007-11-11 19:45:10 +00002588 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2589 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2590 abi_ulong) != 0)
2591 goto do_sigsegv;
2592 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2593 abi_ulong) != 0)
2594 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002595 /* FIXME this does not match how the kernel handles the FPU in
2596 * its sparc64_set_context implementation. In particular the FPU
2597 * is only restored if fenab is non-zero in:
2598 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2599 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002600 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002601 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002602 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2603 for (i = 0; i < 64; i++, src++) {
2604 if (i & 1) {
2605 err |= __get_user(env->fpr[i/2].l.lower, src);
2606 } else {
2607 err |= __get_user(env->fpr[i/2].l.upper, src);
2608 }
2609 }
bellard459a4012007-11-11 19:45:10 +00002610 }
bellard579a97f2007-11-11 14:26:47 +00002611 err |= __get_user(env->fsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002612 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
bellard579a97f2007-11-11 14:26:47 +00002613 err |= __get_user(env->gsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002614 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002615 if (err)
2616 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002617 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002618 return;
2619 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002620 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002621 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002622}
2623
2624void sparc64_get_context(CPUSPARCState *env)
2625{
bellard459a4012007-11-11 19:45:10 +00002626 abi_ulong ucp_addr;
2627 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002628 target_mc_gregset_t *grp;
2629 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002630 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002631 int err;
2632 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002633 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002634 sigset_t set;
2635
bellard459a4012007-11-11 19:45:10 +00002636 ucp_addr = env->regwptr[UREG_I0];
2637 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2638 goto do_sigsegv;
2639
Aurelien Jarno60e99242010-03-29 02:12:51 +02002640 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002641 grp = &mcp->mc_gregs;
2642
2643 /* Skip over the trap instruction, first. */
2644 env->pc = env->npc;
2645 env->npc += 4;
2646
2647 err = 0;
2648
2649 sigprocmask(0, NULL, &set);
2650 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002651 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002652 err |= __put_user(target_set.sig[0],
Aurelien Jarno60e99242010-03-29 02:12:51 +02002653 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002654 } else {
2655 abi_ulong *src, *dst;
2656 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002657 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002658 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002659 err |= __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002660 }
blueswir15bfb56b2007-10-05 17:01:51 +00002661 if (err)
2662 goto do_sigsegv;
2663 }
2664
bellard459a4012007-11-11 19:45:10 +00002665 /* XXX: tstate must be saved properly */
2666 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002667 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2668 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2669 err |= __put_user(env->y, &((*grp)[MC_Y]));
2670 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2671 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2672 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2673 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2674 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2675 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2676 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2677 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2678 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2679 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2680 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2681 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2682 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2683 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2684 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002685
bellard459a4012007-11-11 19:45:10 +00002686 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2687 fp = i7 = 0;
2688 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2689 abi_ulong) != 0)
2690 goto do_sigsegv;
2691 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2692 abi_ulong) != 0)
2693 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002694 err |= __put_user(fp, &(mcp->mc_fp));
2695 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002696
bellard459a4012007-11-11 19:45:10 +00002697 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002698 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2699 for (i = 0; i < 64; i++, dst++) {
2700 if (i & 1) {
2701 err |= __put_user(env->fpr[i/2].l.lower, dst);
2702 } else {
2703 err |= __put_user(env->fpr[i/2].l.upper, dst);
2704 }
2705 }
bellard459a4012007-11-11 19:45:10 +00002706 }
bellard579a97f2007-11-11 14:26:47 +00002707 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2708 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2709 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002710
2711 if (err)
2712 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002713 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002714 return;
2715 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002716 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002717 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002718}
2719#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002720#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002721
Richard Hendersonff970902013-02-10 10:30:42 -08002722# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002723struct target_sigcontext {
2724 uint32_t sc_regmask; /* Unused */
2725 uint32_t sc_status;
2726 uint64_t sc_pc;
2727 uint64_t sc_regs[32];
2728 uint64_t sc_fpregs[32];
2729 uint32_t sc_ownedfp; /* Unused */
2730 uint32_t sc_fpc_csr;
2731 uint32_t sc_fpc_eir; /* Unused */
2732 uint32_t sc_used_math;
2733 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002734 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002735 uint64_t sc_mdhi;
2736 uint64_t sc_mdlo;
2737 target_ulong sc_hi1; /* Was sc_cause */
2738 target_ulong sc_lo1; /* Was sc_badvaddr */
2739 target_ulong sc_hi2; /* Was sc_sigset[4] */
2740 target_ulong sc_lo2;
2741 target_ulong sc_hi3;
2742 target_ulong sc_lo3;
2743};
Richard Hendersonff970902013-02-10 10:30:42 -08002744# else /* N32 || N64 */
2745struct target_sigcontext {
2746 uint64_t sc_regs[32];
2747 uint64_t sc_fpregs[32];
2748 uint64_t sc_mdhi;
2749 uint64_t sc_hi1;
2750 uint64_t sc_hi2;
2751 uint64_t sc_hi3;
2752 uint64_t sc_mdlo;
2753 uint64_t sc_lo1;
2754 uint64_t sc_lo2;
2755 uint64_t sc_lo3;
2756 uint64_t sc_pc;
2757 uint32_t sc_fpc_csr;
2758 uint32_t sc_used_math;
2759 uint32_t sc_dsp;
2760 uint32_t sc_reserved;
2761};
2762# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002763
2764struct sigframe {
2765 uint32_t sf_ass[4]; /* argument save space for o32 */
2766 uint32_t sf_code[2]; /* signal trampoline */
2767 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002768 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002769};
2770
pbrook0b1bcb02009-04-21 01:41:10 +00002771struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002772 target_ulong tuc_flags;
2773 target_ulong tuc_link;
2774 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002775 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002776 struct target_sigcontext tuc_mcontext;
2777 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002778};
2779
2780struct target_rt_sigframe {
2781 uint32_t rs_ass[4]; /* argument save space for o32 */
2782 uint32_t rs_code[2]; /* signal trampoline */
2783 struct target_siginfo rs_info;
2784 struct target_ucontext rs_uc;
2785};
2786
bellard106ec872006-06-27 21:08:10 +00002787/* Install trampoline to jump back from signal handler */
2788static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2789{
Richard Henderson084d0492013-02-10 10:30:44 -08002790 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002791
2792 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002793 * Set up the return code ...
2794 *
2795 * li v0, __NR__foo_sigreturn
2796 * syscall
2797 */
bellard106ec872006-06-27 21:08:10 +00002798
Richard Henderson084d0492013-02-10 10:30:44 -08002799 err |= __put_user(0x24020000 + syscall, tramp + 0);
bellard106ec872006-06-27 21:08:10 +00002800 err |= __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002801 return err;
2802}
2803
2804static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002805setup_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002806{
2807 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002808 int i;
bellard106ec872006-06-27 21:08:10 +00002809
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002810 err |= __put_user(exception_resume_pc(regs), &sc->sc_pc);
2811 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002812
Richard Henderson084d0492013-02-10 10:30:44 -08002813 __put_user(0, &sc->sc_regs[0]);
2814 for (i = 1; i < 32; ++i) {
2815 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
2816 }
bellard106ec872006-06-27 21:08:10 +00002817
thsb5dc7732008-06-27 10:02:35 +00002818 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2819 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002820
Richard Henderson084d0492013-02-10 10:30:44 -08002821 /* Rather than checking for dsp existence, always copy. The storage
2822 would just be garbage otherwise. */
2823 err |= __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2824 err |= __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2825 err |= __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2826 err |= __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2827 err |= __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2828 err |= __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
2829 {
2830 uint32_t dsp = cpu_rddsp(0x3ff, regs);
2831 err |= __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002832 }
Richard Henderson084d0492013-02-10 10:30:44 -08002833
2834 err |= __put_user(1, &sc->sc_used_math);
2835
2836 for (i = 0; i < 32; ++i) {
2837 err |= __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002838 }
bellard106ec872006-06-27 21:08:10 +00002839
bellard106ec872006-06-27 21:08:10 +00002840 return err;
2841}
2842
2843static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002844restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002845{
2846 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002847 int i;
bellard106ec872006-06-27 21:08:10 +00002848
2849 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2850
thsb5dc7732008-06-27 10:02:35 +00002851 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2852 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002853
Richard Henderson084d0492013-02-10 10:30:44 -08002854 for (i = 1; i < 32; ++i) {
2855 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002856 }
2857
Richard Henderson084d0492013-02-10 10:30:44 -08002858 err |= __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2859 err |= __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2860 err |= __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2861 err |= __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2862 err |= __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2863 err |= __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
2864 {
2865 uint32_t dsp;
2866 err |= __get_user(dsp, &sc->sc_dsp);
2867 cpu_wrdsp(dsp, 0x3ff, regs);
2868 }
2869
2870 for (i = 0; i < 32; ++i) {
2871 err |= __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
2872 }
2873
bellard106ec872006-06-27 21:08:10 +00002874 return err;
2875}
Richard Hendersonff970902013-02-10 10:30:42 -08002876
bellard106ec872006-06-27 21:08:10 +00002877/*
2878 * Determine which stack to use..
2879 */
bellard579a97f2007-11-11 14:26:47 +00002880static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002881get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002882{
2883 unsigned long sp;
2884
2885 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002886 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002887
2888 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002889 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002890 * above the user stack, 16-bytes before the next lowest
2891 * 16 byte boundary. Try to avoid trashing it.
2892 */
2893 sp -= 32;
2894
bellard106ec872006-06-27 21:08:10 +00002895 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002896 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002897 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2898 }
bellard106ec872006-06-27 21:08:10 +00002899
bellard579a97f2007-11-11 14:26:47 +00002900 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002901}
2902
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002903static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2904{
2905 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2906 env->hflags &= ~MIPS_HFLAG_M16;
2907 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2908 env->active_tc.PC &= ~(target_ulong) 1;
2909 }
2910}
2911
Richard Hendersonff970902013-02-10 10:30:42 -08002912# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002913/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002914static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002915 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002916{
2917 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002918 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002919 int i;
2920
bellard579a97f2007-11-11 14:26:47 +00002921 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2922 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002923 goto give_sigsegv;
2924
2925 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2926
2927 if(setup_sigcontext(regs, &frame->sf_sc))
2928 goto give_sigsegv;
2929
2930 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2931 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2932 goto give_sigsegv;
2933 }
2934
2935 /*
2936 * Arguments to signal handler:
2937 *
2938 * a0 = signal number
2939 * a1 = 0 (should be cause)
2940 * a2 = pointer to struct sigcontext
2941 *
2942 * $25 and PC point to the signal handler, $29 points to the
2943 * struct sigframe.
2944 */
thsb5dc7732008-06-27 10:02:35 +00002945 regs->active_tc.gpr[ 4] = sig;
2946 regs->active_tc.gpr[ 5] = 0;
2947 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2948 regs->active_tc.gpr[29] = frame_addr;
2949 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002950 /* The original kernel code sets CP0_EPC to the handler
2951 * since it returns to userland using eret
2952 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002953 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002954 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002955 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002956 return;
2957
2958give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002959 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002960 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002961}
2962
Andreas Färber05390242012-02-25 03:37:53 +01002963long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002964{
ths388bb212007-05-13 13:58:00 +00002965 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002966 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002967 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002968 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002969 int i;
bellard106ec872006-06-27 21:08:10 +00002970
2971#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002972 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002973#endif
thsb5dc7732008-06-27 10:02:35 +00002974 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002975 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002976 goto badframe;
2977
ths388bb212007-05-13 13:58:00 +00002978 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002979 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2980 goto badframe;
ths388bb212007-05-13 13:58:00 +00002981 }
bellard106ec872006-06-27 21:08:10 +00002982
ths388bb212007-05-13 13:58:00 +00002983 target_to_host_sigset_internal(&blocked, &target_set);
2984 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002985
ths388bb212007-05-13 13:58:00 +00002986 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002987 goto badframe;
2988
2989#if 0
ths388bb212007-05-13 13:58:00 +00002990 /*
2991 * Don't let your children do this ...
2992 */
2993 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002994 "move\t$29, %0\n\t"
2995 "j\tsyscall_exit"
2996 :/* no outputs */
2997 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002998 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002999#endif
ths3b46e622007-09-17 08:09:54 +00003000
thsb5dc7732008-06-27 10:02:35 +00003001 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003002 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003003 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003004 * maybe a problem with nested signals ? */
3005 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003006 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003007
3008badframe:
ths388bb212007-05-13 13:58:00 +00003009 force_sig(TARGET_SIGSEGV/*, current*/);
3010 return 0;
bellard106ec872006-06-27 21:08:10 +00003011}
Richard Hendersonff970902013-02-10 10:30:42 -08003012# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003013
pbrook624f7972008-05-31 16:11:38 +00003014static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003015 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003016 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003017{
pbrook0b1bcb02009-04-21 01:41:10 +00003018 struct target_rt_sigframe *frame;
3019 abi_ulong frame_addr;
3020 int i;
3021
3022 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3023 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3024 goto give_sigsegv;
3025
3026 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3027
3028 copy_siginfo_to_user(&frame->rs_info, info);
3029
Aurelien Jarno60e99242010-03-29 02:12:51 +02003030 __put_user(0, &frame->rs_uc.tuc_flags);
3031 __put_user(0, &frame->rs_uc.tuc_link);
3032 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3033 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003034 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003035 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003036
Aurelien Jarno60e99242010-03-29 02:12:51 +02003037 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003038
3039 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003040 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003041 }
3042
3043 /*
3044 * Arguments to signal handler:
3045 *
3046 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003047 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003048 * a2 = pointer to struct ucontext
3049 *
3050 * $25 and PC point to the signal handler, $29 points to the
3051 * struct sigframe.
3052 */
3053 env->active_tc.gpr[ 4] = sig;
3054 env->active_tc.gpr[ 5] = frame_addr
3055 + offsetof(struct target_rt_sigframe, rs_info);
3056 env->active_tc.gpr[ 6] = frame_addr
3057 + offsetof(struct target_rt_sigframe, rs_uc);
3058 env->active_tc.gpr[29] = frame_addr;
3059 env->active_tc.gpr[31] = frame_addr
3060 + offsetof(struct target_rt_sigframe, rs_code);
3061 /* The original kernel code sets CP0_EPC to the handler
3062 * since it returns to userland using eret
3063 * we cannot do this here, and we must set PC directly */
3064 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003065 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003066 unlock_user_struct(frame, frame_addr, 1);
3067 return;
3068
3069give_sigsegv:
3070 unlock_user_struct(frame, frame_addr, 1);
3071 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003072}
3073
Andreas Färber05390242012-02-25 03:37:53 +01003074long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003075{
pbrook0b1bcb02009-04-21 01:41:10 +00003076 struct target_rt_sigframe *frame;
3077 abi_ulong frame_addr;
3078 sigset_t blocked;
3079
3080#if defined(DEBUG_SIGNAL)
3081 fprintf(stderr, "do_rt_sigreturn\n");
3082#endif
3083 frame_addr = env->active_tc.gpr[29];
3084 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3085 goto badframe;
3086
Aurelien Jarno60e99242010-03-29 02:12:51 +02003087 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
pbrook0b1bcb02009-04-21 01:41:10 +00003088 sigprocmask(SIG_SETMASK, &blocked, NULL);
3089
Aurelien Jarno60e99242010-03-29 02:12:51 +02003090 if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
pbrook0b1bcb02009-04-21 01:41:10 +00003091 goto badframe;
3092
3093 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003094 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003095 0, get_sp_from_cpustate(env)) == -EFAULT)
3096 goto badframe;
3097
3098 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003099 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003100 /* I am not sure this is right, but it seems to work
3101 * maybe a problem with nested signals ? */
3102 env->CP0_EPC = 0;
3103 return -TARGET_QEMU_ESIGRETURN;
3104
3105badframe:
3106 force_sig(TARGET_SIGSEGV/*, current*/);
3107 return 0;
bellard106ec872006-06-27 21:08:10 +00003108}
bellard6d5e2162004-09-30 22:04:13 +00003109
thsc3b5bc82007-12-02 06:31:25 +00003110#elif defined(TARGET_SH4)
3111
3112/*
3113 * code and data structures from linux kernel:
3114 * include/asm-sh/sigcontext.h
3115 * arch/sh/kernel/signal.c
3116 */
3117
3118struct target_sigcontext {
3119 target_ulong oldmask;
3120
3121 /* CPU registers */
3122 target_ulong sc_gregs[16];
3123 target_ulong sc_pc;
3124 target_ulong sc_pr;
3125 target_ulong sc_sr;
3126 target_ulong sc_gbr;
3127 target_ulong sc_mach;
3128 target_ulong sc_macl;
3129
3130 /* FPU registers */
3131 target_ulong sc_fpregs[16];
3132 target_ulong sc_xfpregs[16];
3133 unsigned int sc_fpscr;
3134 unsigned int sc_fpul;
3135 unsigned int sc_ownedfp;
3136};
3137
3138struct target_sigframe
3139{
3140 struct target_sigcontext sc;
3141 target_ulong extramask[TARGET_NSIG_WORDS-1];
3142 uint16_t retcode[3];
3143};
3144
3145
3146struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003147 target_ulong tuc_flags;
3148 struct target_ucontext *tuc_link;
3149 target_stack_t tuc_stack;
3150 struct target_sigcontext tuc_mcontext;
3151 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003152};
3153
3154struct target_rt_sigframe
3155{
3156 struct target_siginfo info;
3157 struct target_ucontext uc;
3158 uint16_t retcode[3];
3159};
3160
3161
3162#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3163#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3164
pbrook624f7972008-05-31 16:11:38 +00003165static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003166 unsigned long sp, size_t frame_size)
3167{
pbrook624f7972008-05-31 16:11:38 +00003168 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003169 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3170 }
3171
3172 return (sp - frame_size) & -8ul;
3173}
3174
3175static int setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003176 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003177{
3178 int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003179 int i;
thsc3b5bc82007-12-02 06:31:25 +00003180
3181#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
3182 COPY(gregs[0]); COPY(gregs[1]);
3183 COPY(gregs[2]); COPY(gregs[3]);
3184 COPY(gregs[4]); COPY(gregs[5]);
3185 COPY(gregs[6]); COPY(gregs[7]);
3186 COPY(gregs[8]); COPY(gregs[9]);
3187 COPY(gregs[10]); COPY(gregs[11]);
3188 COPY(gregs[12]); COPY(gregs[13]);
3189 COPY(gregs[14]); COPY(gregs[15]);
3190 COPY(gbr); COPY(mach);
3191 COPY(macl); COPY(pr);
3192 COPY(sr); COPY(pc);
3193#undef COPY
3194
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003195 for (i=0; i<16; i++) {
3196 err |= __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
3197 }
3198 err |= __put_user(regs->fpscr, &sc->sc_fpscr);
3199 err |= __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003200
3201 /* non-iBCS2 extensions.. */
3202 err |= __put_user(mask, &sc->oldmask);
3203
3204 return err;
3205}
3206
Andreas Färber05390242012-02-25 03:37:53 +01003207static int restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003208 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003209{
3210 unsigned int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003211 int i;
thsc3b5bc82007-12-02 06:31:25 +00003212
3213#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
3214 COPY(gregs[1]);
3215 COPY(gregs[2]); COPY(gregs[3]);
3216 COPY(gregs[4]); COPY(gregs[5]);
3217 COPY(gregs[6]); COPY(gregs[7]);
3218 COPY(gregs[8]); COPY(gregs[9]);
3219 COPY(gregs[10]); COPY(gregs[11]);
3220 COPY(gregs[12]); COPY(gregs[13]);
3221 COPY(gregs[14]); COPY(gregs[15]);
3222 COPY(gbr); COPY(mach);
3223 COPY(macl); COPY(pr);
3224 COPY(sr); COPY(pc);
3225#undef COPY
3226
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003227 for (i=0; i<16; i++) {
3228 err |= __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
3229 }
3230 err |= __get_user(regs->fpscr, &sc->sc_fpscr);
3231 err |= __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003232
3233 regs->tra = -1; /* disable syscall checks */
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003234 err |= __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003235 return err;
3236}
3237
pbrook624f7972008-05-31 16:11:38 +00003238static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003239 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003240{
3241 struct target_sigframe *frame;
3242 abi_ulong frame_addr;
3243 int i;
3244 int err = 0;
3245 int signal;
3246
3247 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3248 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3249 goto give_sigsegv;
3250
3251 signal = current_exec_domain_sig(sig);
3252
3253 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
3254
3255 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
3256 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
3257 }
3258
3259 /* Set up to return from userspace. If provided, use a stub
3260 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003261 if (ka->sa_flags & TARGET_SA_RESTORER) {
3262 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003263 } else {
3264 /* Generate return code (system call to sigreturn) */
3265 err |= __put_user(MOVW(2), &frame->retcode[0]);
3266 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3267 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
3268 regs->pr = (unsigned long) frame->retcode;
3269 }
3270
3271 if (err)
3272 goto give_sigsegv;
3273
3274 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003275 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003276 regs->gregs[4] = signal; /* Arg for signal handler */
3277 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003278 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003279 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003280
3281 unlock_user_struct(frame, frame_addr, 1);
3282 return;
3283
3284give_sigsegv:
3285 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003286 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003287}
3288
pbrook624f7972008-05-31 16:11:38 +00003289static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003290 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003291 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003292{
3293 struct target_rt_sigframe *frame;
3294 abi_ulong frame_addr;
3295 int i;
3296 int err = 0;
3297 int signal;
3298
3299 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3300 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3301 goto give_sigsegv;
3302
3303 signal = current_exec_domain_sig(sig);
3304
3305 err |= copy_siginfo_to_user(&frame->info, info);
3306
3307 /* Create the ucontext. */
Aurelien Jarno60e99242010-03-29 02:12:51 +02003308 err |= __put_user(0, &frame->uc.tuc_flags);
3309 err |= __put_user(0, (unsigned long *)&frame->uc.tuc_link);
balrog526ccb72008-07-16 12:13:52 +00003310 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003311 &frame->uc.tuc_stack.ss_sp);
thsc3b5bc82007-12-02 06:31:25 +00003312 err |= __put_user(sas_ss_flags(regs->gregs[15]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003313 &frame->uc.tuc_stack.ss_flags);
thsc3b5bc82007-12-02 06:31:25 +00003314 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003315 &frame->uc.tuc_stack.ss_size);
3316 err |= setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003317 regs, set->sig[0]);
3318 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003319 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003320 }
3321
3322 /* Set up to return from userspace. If provided, use a stub
3323 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003324 if (ka->sa_flags & TARGET_SA_RESTORER) {
3325 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003326 } else {
3327 /* Generate return code (system call to sigreturn) */
3328 err |= __put_user(MOVW(2), &frame->retcode[0]);
3329 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3330 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
3331 regs->pr = (unsigned long) frame->retcode;
3332 }
3333
3334 if (err)
3335 goto give_sigsegv;
3336
3337 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003338 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003339 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003340 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3341 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003342 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003343
3344 unlock_user_struct(frame, frame_addr, 1);
3345 return;
3346
3347give_sigsegv:
3348 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003349 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003350}
3351
Andreas Färber05390242012-02-25 03:37:53 +01003352long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003353{
3354 struct target_sigframe *frame;
3355 abi_ulong frame_addr;
3356 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003357 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003358 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003359 int i;
3360 int err = 0;
3361
3362#if defined(DEBUG_SIGNAL)
3363 fprintf(stderr, "do_sigreturn\n");
3364#endif
3365 frame_addr = regs->gregs[15];
3366 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3367 goto badframe;
3368
3369 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
3370 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3371 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
3372 }
3373
3374 if (err)
3375 goto badframe;
3376
3377 target_to_host_sigset_internal(&blocked, &target_set);
3378 sigprocmask(SIG_SETMASK, &blocked, NULL);
3379
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003380 if (restore_sigcontext(regs, &frame->sc, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003381 goto badframe;
3382
3383 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003384 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003385
3386badframe:
3387 unlock_user_struct(frame, frame_addr, 0);
3388 force_sig(TARGET_SIGSEGV);
3389 return 0;
3390}
3391
Andreas Färber05390242012-02-25 03:37:53 +01003392long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003393{
3394 struct target_rt_sigframe *frame;
3395 abi_ulong frame_addr;
3396 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003397 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003398
3399#if defined(DEBUG_SIGNAL)
3400 fprintf(stderr, "do_rt_sigreturn\n");
3401#endif
3402 frame_addr = regs->gregs[15];
3403 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3404 goto badframe;
3405
Aurelien Jarno60e99242010-03-29 02:12:51 +02003406 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
thsc3b5bc82007-12-02 06:31:25 +00003407 sigprocmask(SIG_SETMASK, &blocked, NULL);
3408
Aurelien Jarno60e99242010-03-29 02:12:51 +02003409 if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003410 goto badframe;
3411
3412 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003413 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003414 0, get_sp_from_cpustate(regs)) == -EFAULT)
3415 goto badframe;
3416
3417 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003418 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003419
3420badframe:
3421 unlock_user_struct(frame, frame_addr, 0);
3422 force_sig(TARGET_SIGSEGV);
3423 return 0;
3424}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003425#elif defined(TARGET_MICROBLAZE)
3426
3427struct target_sigcontext {
3428 struct target_pt_regs regs; /* needs to be first */
3429 uint32_t oldmask;
3430};
3431
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003432struct target_stack_t {
3433 abi_ulong ss_sp;
3434 int ss_flags;
3435 unsigned int ss_size;
3436};
3437
3438struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003439 abi_ulong tuc_flags;
3440 abi_ulong tuc_link;
3441 struct target_stack_t tuc_stack;
3442 struct target_sigcontext tuc_mcontext;
3443 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003444};
3445
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003446/* Signal frames. */
3447struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003448 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003449 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3450 uint32_t tramp[2];
3451};
3452
3453struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003454 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003455 struct ucontext uc;
3456 uint32_t tramp[2];
3457};
3458
Andreas Färber05390242012-02-25 03:37:53 +01003459static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003460{
3461 __put_user(env->regs[0], &sc->regs.r0);
3462 __put_user(env->regs[1], &sc->regs.r1);
3463 __put_user(env->regs[2], &sc->regs.r2);
3464 __put_user(env->regs[3], &sc->regs.r3);
3465 __put_user(env->regs[4], &sc->regs.r4);
3466 __put_user(env->regs[5], &sc->regs.r5);
3467 __put_user(env->regs[6], &sc->regs.r6);
3468 __put_user(env->regs[7], &sc->regs.r7);
3469 __put_user(env->regs[8], &sc->regs.r8);
3470 __put_user(env->regs[9], &sc->regs.r9);
3471 __put_user(env->regs[10], &sc->regs.r10);
3472 __put_user(env->regs[11], &sc->regs.r11);
3473 __put_user(env->regs[12], &sc->regs.r12);
3474 __put_user(env->regs[13], &sc->regs.r13);
3475 __put_user(env->regs[14], &sc->regs.r14);
3476 __put_user(env->regs[15], &sc->regs.r15);
3477 __put_user(env->regs[16], &sc->regs.r16);
3478 __put_user(env->regs[17], &sc->regs.r17);
3479 __put_user(env->regs[18], &sc->regs.r18);
3480 __put_user(env->regs[19], &sc->regs.r19);
3481 __put_user(env->regs[20], &sc->regs.r20);
3482 __put_user(env->regs[21], &sc->regs.r21);
3483 __put_user(env->regs[22], &sc->regs.r22);
3484 __put_user(env->regs[23], &sc->regs.r23);
3485 __put_user(env->regs[24], &sc->regs.r24);
3486 __put_user(env->regs[25], &sc->regs.r25);
3487 __put_user(env->regs[26], &sc->regs.r26);
3488 __put_user(env->regs[27], &sc->regs.r27);
3489 __put_user(env->regs[28], &sc->regs.r28);
3490 __put_user(env->regs[29], &sc->regs.r29);
3491 __put_user(env->regs[30], &sc->regs.r30);
3492 __put_user(env->regs[31], &sc->regs.r31);
3493 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3494}
3495
Andreas Färber05390242012-02-25 03:37:53 +01003496static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003497{
3498 __get_user(env->regs[0], &sc->regs.r0);
3499 __get_user(env->regs[1], &sc->regs.r1);
3500 __get_user(env->regs[2], &sc->regs.r2);
3501 __get_user(env->regs[3], &sc->regs.r3);
3502 __get_user(env->regs[4], &sc->regs.r4);
3503 __get_user(env->regs[5], &sc->regs.r5);
3504 __get_user(env->regs[6], &sc->regs.r6);
3505 __get_user(env->regs[7], &sc->regs.r7);
3506 __get_user(env->regs[8], &sc->regs.r8);
3507 __get_user(env->regs[9], &sc->regs.r9);
3508 __get_user(env->regs[10], &sc->regs.r10);
3509 __get_user(env->regs[11], &sc->regs.r11);
3510 __get_user(env->regs[12], &sc->regs.r12);
3511 __get_user(env->regs[13], &sc->regs.r13);
3512 __get_user(env->regs[14], &sc->regs.r14);
3513 __get_user(env->regs[15], &sc->regs.r15);
3514 __get_user(env->regs[16], &sc->regs.r16);
3515 __get_user(env->regs[17], &sc->regs.r17);
3516 __get_user(env->regs[18], &sc->regs.r18);
3517 __get_user(env->regs[19], &sc->regs.r19);
3518 __get_user(env->regs[20], &sc->regs.r20);
3519 __get_user(env->regs[21], &sc->regs.r21);
3520 __get_user(env->regs[22], &sc->regs.r22);
3521 __get_user(env->regs[23], &sc->regs.r23);
3522 __get_user(env->regs[24], &sc->regs.r24);
3523 __get_user(env->regs[25], &sc->regs.r25);
3524 __get_user(env->regs[26], &sc->regs.r26);
3525 __get_user(env->regs[27], &sc->regs.r27);
3526 __get_user(env->regs[28], &sc->regs.r28);
3527 __get_user(env->regs[29], &sc->regs.r29);
3528 __get_user(env->regs[30], &sc->regs.r30);
3529 __get_user(env->regs[31], &sc->regs.r31);
3530 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3531}
3532
3533static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003534 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003535{
3536 abi_ulong sp = env->regs[1];
3537
3538 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3539 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3540
3541 return ((sp - frame_size) & -8UL);
3542}
3543
3544static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003545 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003546{
3547 struct target_signal_frame *frame;
3548 abi_ulong frame_addr;
3549 int err = 0;
3550 int i;
3551
3552 frame_addr = get_sigframe(ka, env, sizeof *frame);
3553 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3554 goto badframe;
3555
3556 /* Save the mask. */
Richard Hendersonf711df62010-11-22 14:57:52 -08003557 err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003558 if (err)
3559 goto badframe;
3560
3561 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3562 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3563 goto badframe;
3564 }
3565
Richard Hendersonf711df62010-11-22 14:57:52 -08003566 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003567
3568 /* Set up to return from userspace. If provided, use a stub
3569 already in userspace. */
3570 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3571 if (ka->sa_flags & TARGET_SA_RESTORER) {
3572 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3573 } else {
3574 uint32_t t;
3575 /* Note, these encodings are _big endian_! */
3576 /* addi r12, r0, __NR_sigreturn */
3577 t = 0x31800000UL | TARGET_NR_sigreturn;
3578 err |= __put_user(t, frame->tramp + 0);
3579 /* brki r14, 0x8 */
3580 t = 0xb9cc0008UL;
3581 err |= __put_user(t, frame->tramp + 1);
3582
3583 /* Return from sighandler will jump to the tramp.
3584 Negative 8 offset because return is rtsd r15, 8 */
3585 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3586 }
3587
3588 if (err)
3589 goto badframe;
3590
3591 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003592 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003593 /* Signal handler args: */
3594 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003595 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003596 /* arg 1: sigcontext */
3597 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003598
3599 /* Offset of 4 to handle microblaze rtid r14, 0 */
3600 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3601
3602 unlock_user_struct(frame, frame_addr, 1);
3603 return;
3604 badframe:
3605 unlock_user_struct(frame, frame_addr, 1);
3606 force_sig(TARGET_SIGSEGV);
3607}
3608
3609static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003610 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003611 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003612{
3613 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3614}
3615
Andreas Färber05390242012-02-25 03:37:53 +01003616long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003617{
3618 struct target_signal_frame *frame;
3619 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003620 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003621 sigset_t set;
3622 int i;
3623
3624 frame_addr = env->regs[R_SP];
3625 /* Make sure the guest isn't playing games. */
3626 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3627 goto badframe;
3628
3629 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003630 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003631 goto badframe;
3632 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3633 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3634 goto badframe;
3635 }
3636 target_to_host_sigset_internal(&set, &target_set);
3637 sigprocmask(SIG_SETMASK, &set, NULL);
3638
Richard Hendersonf711df62010-11-22 14:57:52 -08003639 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003640 /* We got here through a sigreturn syscall, our path back is via an
3641 rtb insn so setup r14 for that. */
3642 env->regs[14] = env->sregs[SR_PC];
3643
3644 unlock_user_struct(frame, frame_addr, 0);
3645 return env->regs[10];
3646 badframe:
3647 unlock_user_struct(frame, frame_addr, 0);
3648 force_sig(TARGET_SIGSEGV);
3649}
3650
Andreas Färber05390242012-02-25 03:37:53 +01003651long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003652{
3653 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3654 return -TARGET_ENOSYS;
3655}
3656
edgar_iglb6d3abd2008-02-28 11:29:27 +00003657#elif defined(TARGET_CRIS)
3658
3659struct target_sigcontext {
3660 struct target_pt_regs regs; /* needs to be first */
3661 uint32_t oldmask;
3662 uint32_t usp; /* usp before stacking this gunk on it */
3663};
3664
3665/* Signal frames. */
3666struct target_signal_frame {
3667 struct target_sigcontext sc;
3668 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003669 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003670};
3671
3672struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003673 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003674 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003675 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003676 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003677 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003678};
3679
Andreas Färber05390242012-02-25 03:37:53 +01003680static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003681{
edgar_igl9664d922008-03-03 22:23:53 +00003682 __put_user(env->regs[0], &sc->regs.r0);
3683 __put_user(env->regs[1], &sc->regs.r1);
3684 __put_user(env->regs[2], &sc->regs.r2);
3685 __put_user(env->regs[3], &sc->regs.r3);
3686 __put_user(env->regs[4], &sc->regs.r4);
3687 __put_user(env->regs[5], &sc->regs.r5);
3688 __put_user(env->regs[6], &sc->regs.r6);
3689 __put_user(env->regs[7], &sc->regs.r7);
3690 __put_user(env->regs[8], &sc->regs.r8);
3691 __put_user(env->regs[9], &sc->regs.r9);
3692 __put_user(env->regs[10], &sc->regs.r10);
3693 __put_user(env->regs[11], &sc->regs.r11);
3694 __put_user(env->regs[12], &sc->regs.r12);
3695 __put_user(env->regs[13], &sc->regs.r13);
3696 __put_user(env->regs[14], &sc->usp);
3697 __put_user(env->regs[15], &sc->regs.acr);
3698 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3699 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3700 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003701}
edgar_igl9664d922008-03-03 22:23:53 +00003702
Andreas Färber05390242012-02-25 03:37:53 +01003703static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003704{
edgar_igl9664d922008-03-03 22:23:53 +00003705 __get_user(env->regs[0], &sc->regs.r0);
3706 __get_user(env->regs[1], &sc->regs.r1);
3707 __get_user(env->regs[2], &sc->regs.r2);
3708 __get_user(env->regs[3], &sc->regs.r3);
3709 __get_user(env->regs[4], &sc->regs.r4);
3710 __get_user(env->regs[5], &sc->regs.r5);
3711 __get_user(env->regs[6], &sc->regs.r6);
3712 __get_user(env->regs[7], &sc->regs.r7);
3713 __get_user(env->regs[8], &sc->regs.r8);
3714 __get_user(env->regs[9], &sc->regs.r9);
3715 __get_user(env->regs[10], &sc->regs.r10);
3716 __get_user(env->regs[11], &sc->regs.r11);
3717 __get_user(env->regs[12], &sc->regs.r12);
3718 __get_user(env->regs[13], &sc->regs.r13);
3719 __get_user(env->regs[14], &sc->usp);
3720 __get_user(env->regs[15], &sc->regs.acr);
3721 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3722 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3723 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003724}
3725
Andreas Färber05390242012-02-25 03:37:53 +01003726static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003727{
edgar_igl9664d922008-03-03 22:23:53 +00003728 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003729 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003730 sp = (env->regs[R_SP] & ~3);
3731 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003732}
3733
pbrook624f7972008-05-31 16:11:38 +00003734static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003735 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003736{
3737 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003738 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003739 int err = 0;
3740 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003741
edgar_igl9664d922008-03-03 22:23:53 +00003742 frame_addr = get_sigframe(env, sizeof *frame);
3743 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003744 goto badframe;
3745
3746 /*
3747 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3748 * use this trampoline anymore but it sets it up for GDB.
3749 * In QEMU, using the trampoline simplifies things a bit so we use it.
3750 *
3751 * This is movu.w __NR_sigreturn, r9; break 13;
3752 */
3753 err |= __put_user(0x9c5f, frame->retcode+0);
3754 err |= __put_user(TARGET_NR_sigreturn,
Stefan Weil8cfc1142014-02-01 09:41:09 +01003755 frame->retcode + 1);
3756 err |= __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003757
3758 /* Save the mask. */
3759 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3760 if (err)
3761 goto badframe;
3762
3763 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3764 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3765 goto badframe;
3766 }
3767
3768 setup_sigcontext(&frame->sc, env);
3769
3770 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003771 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003772 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003773 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003774 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003775 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003776
edgar_igl9664d922008-03-03 22:23:53 +00003777 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003778 return;
3779 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003780 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003781 force_sig(TARGET_SIGSEGV);
3782}
3783
pbrook624f7972008-05-31 16:11:38 +00003784static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003785 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003786 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003787{
3788 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3789}
3790
Andreas Färber05390242012-02-25 03:37:53 +01003791long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003792{
3793 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003794 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003795 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003796 sigset_t set;
3797 int i;
3798
edgar_igl9664d922008-03-03 22:23:53 +00003799 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003800 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003801 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003802 goto badframe;
3803
3804 /* Restore blocked signals */
3805 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3806 goto badframe;
3807 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3808 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3809 goto badframe;
3810 }
3811 target_to_host_sigset_internal(&set, &target_set);
3812 sigprocmask(SIG_SETMASK, &set, NULL);
3813
3814 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003815 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003816 return env->regs[10];
3817 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003818 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003819 force_sig(TARGET_SIGSEGV);
3820}
3821
Andreas Färber05390242012-02-25 03:37:53 +01003822long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003823{
3824 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3825 return -TARGET_ENOSYS;
3826}
thsc3b5bc82007-12-02 06:31:25 +00003827
Jia Liud9627832012-07-20 15:50:52 +08003828#elif defined(TARGET_OPENRISC)
3829
3830struct target_sigcontext {
3831 struct target_pt_regs regs;
3832 abi_ulong oldmask;
3833 abi_ulong usp;
3834};
3835
3836struct target_ucontext {
3837 abi_ulong tuc_flags;
3838 abi_ulong tuc_link;
3839 target_stack_t tuc_stack;
3840 struct target_sigcontext tuc_mcontext;
3841 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3842};
3843
3844struct target_rt_sigframe {
3845 abi_ulong pinfo;
3846 uint64_t puc;
3847 struct target_siginfo info;
3848 struct target_sigcontext sc;
3849 struct target_ucontext uc;
3850 unsigned char retcode[16]; /* trampoline code */
3851};
3852
3853/* This is the asm-generic/ucontext.h version */
3854#if 0
3855static int restore_sigcontext(CPUOpenRISCState *regs,
3856 struct target_sigcontext *sc)
3857{
3858 unsigned int err = 0;
3859 unsigned long old_usp;
3860
3861 /* Alwys make any pending restarted system call return -EINTR */
3862 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3863
3864 /* restore the regs from &sc->regs (same as sc, since regs is first)
3865 * (sc is already checked for VERIFY_READ since the sigframe was
3866 * checked in sys_sigreturn previously)
3867 */
3868
3869 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3870 goto badframe;
3871 }
3872
3873 /* make sure the U-flag is set so user-mode cannot fool us */
3874
3875 regs->sr &= ~SR_SM;
3876
3877 /* restore the old USP as it was before we stacked the sc etc.
3878 * (we cannot just pop the sigcontext since we aligned the sp and
3879 * stuff after pushing it)
3880 */
3881
3882 err |= __get_user(old_usp, &sc->usp);
3883 phx_signal("old_usp 0x%lx", old_usp);
3884
3885 __PHX__ REALLY /* ??? */
3886 wrusp(old_usp);
3887 regs->gpr[1] = old_usp;
3888
3889 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3890 * after this completes, but we don't use that mechanism. maybe we can
3891 * use it now ?
3892 */
3893
3894 return err;
3895
3896badframe:
3897 return 1;
3898}
3899#endif
3900
3901/* Set up a signal frame. */
3902
3903static int setup_sigcontext(struct target_sigcontext *sc,
3904 CPUOpenRISCState *regs,
3905 unsigned long mask)
3906{
3907 int err = 0;
3908 unsigned long usp = regs->gpr[1];
3909
3910 /* copy the regs. they are first in sc so we can use sc directly */
3911
3912 /*err |= copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
3913
3914 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3915 the signal handler. The frametype will be restored to its previous
3916 value in restore_sigcontext. */
3917 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3918
3919 /* then some other stuff */
3920 err |= __put_user(mask, &sc->oldmask);
3921 err |= __put_user(usp, &sc->usp); return err;
3922}
3923
3924static inline unsigned long align_sigframe(unsigned long sp)
3925{
3926 unsigned long i;
3927 i = sp & ~3UL;
3928 return i;
3929}
3930
3931static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3932 CPUOpenRISCState *regs,
3933 size_t frame_size)
3934{
3935 unsigned long sp = regs->gpr[1];
3936 int onsigstack = on_sig_stack(sp);
3937
3938 /* redzone */
3939 /* This is the X/Open sanctioned signal stack switching. */
3940 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3941 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3942 }
3943
3944 sp = align_sigframe(sp - frame_size);
3945
3946 /*
3947 * If we are on the alternate signal stack and would overflow it, don't.
3948 * Return an always-bogus address instead so we will die with SIGSEGV.
3949 */
3950
3951 if (onsigstack && !likely(on_sig_stack(sp))) {
3952 return -1L;
3953 }
3954
3955 return sp;
3956}
3957
3958static void setup_frame(int sig, struct target_sigaction *ka,
3959 target_sigset_t *set, CPUOpenRISCState *env)
3960{
3961 qemu_log("Not implement.\n");
3962}
3963
3964static void setup_rt_frame(int sig, struct target_sigaction *ka,
3965 target_siginfo_t *info,
3966 target_sigset_t *set, CPUOpenRISCState *env)
3967{
3968 int err = 0;
3969 abi_ulong frame_addr;
3970 unsigned long return_ip;
3971 struct target_rt_sigframe *frame;
3972 abi_ulong info_addr, uc_addr;
3973
3974 frame_addr = get_sigframe(ka, env, sizeof *frame);
3975
3976 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3977 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3978 goto give_sigsegv;
3979 }
3980
3981 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
3982 err |= __put_user(info_addr, &frame->pinfo);
3983 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
3984 err |= __put_user(uc_addr, &frame->puc);
3985
3986 if (ka->sa_flags & SA_SIGINFO) {
3987 err |= copy_siginfo_to_user(&frame->info, info);
3988 }
3989 if (err) {
3990 goto give_sigsegv;
3991 }
3992
3993 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
3994 err |= __put_user(0, &frame->uc.tuc_flags);
3995 err |= __put_user(0, &frame->uc.tuc_link);
3996 err |= __put_user(target_sigaltstack_used.ss_sp,
3997 &frame->uc.tuc_stack.ss_sp);
3998 err |= __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3999 err |= __put_user(target_sigaltstack_used.ss_size,
4000 &frame->uc.tuc_stack.ss_size);
4001 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
4002
4003 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4004
4005 if (err) {
4006 goto give_sigsegv;
4007 }
4008
4009 /* trampoline - the desired return ip is the retcode itself */
4010 return_ip = (unsigned long)&frame->retcode;
4011 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
4012 err |= __put_user(0xa960, (short *)(frame->retcode + 0));
4013 err |= __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4014 err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4015 err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
4016
4017 if (err) {
4018 goto give_sigsegv;
4019 }
4020
4021 /* TODO what is the current->exec_domain stuff and invmap ? */
4022
4023 /* Set up registers for signal handler */
4024 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4025 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4026 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4027 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4028 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4029
4030 /* actually move the usp to reflect the stacked frame */
4031 env->gpr[1] = (unsigned long)frame;
4032
4033 return;
4034
4035give_sigsegv:
4036 unlock_user_struct(frame, frame_addr, 1);
4037 if (sig == TARGET_SIGSEGV) {
4038 ka->_sa_handler = TARGET_SIG_DFL;
4039 }
4040 force_sig(TARGET_SIGSEGV);
4041}
4042
4043long do_sigreturn(CPUOpenRISCState *env)
4044{
4045
4046 qemu_log("do_sigreturn: not implemented\n");
4047 return -TARGET_ENOSYS;
4048}
4049
4050long do_rt_sigreturn(CPUOpenRISCState *env)
4051{
4052 qemu_log("do_rt_sigreturn: not implemented\n");
4053 return -TARGET_ENOSYS;
4054}
4055/* TARGET_OPENRISC */
4056
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004057#elif defined(TARGET_S390X)
4058
4059#define __NUM_GPRS 16
4060#define __NUM_FPRS 16
4061#define __NUM_ACRS 16
4062
4063#define S390_SYSCALL_SIZE 2
4064#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4065
4066#define _SIGCONTEXT_NSIG 64
4067#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4068#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4069#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4070#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4071#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4072
4073typedef struct {
4074 target_psw_t psw;
4075 target_ulong gprs[__NUM_GPRS];
4076 unsigned int acrs[__NUM_ACRS];
4077} target_s390_regs_common;
4078
4079typedef struct {
4080 unsigned int fpc;
4081 double fprs[__NUM_FPRS];
4082} target_s390_fp_regs;
4083
4084typedef struct {
4085 target_s390_regs_common regs;
4086 target_s390_fp_regs fpregs;
4087} target_sigregs;
4088
4089struct target_sigcontext {
4090 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4091 target_sigregs *sregs;
4092};
4093
4094typedef struct {
4095 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4096 struct target_sigcontext sc;
4097 target_sigregs sregs;
4098 int signo;
4099 uint8_t retcode[S390_SYSCALL_SIZE];
4100} sigframe;
4101
4102struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004103 target_ulong tuc_flags;
4104 struct target_ucontext *tuc_link;
4105 target_stack_t tuc_stack;
4106 target_sigregs tuc_mcontext;
4107 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004108};
4109
4110typedef struct {
4111 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4112 uint8_t retcode[S390_SYSCALL_SIZE];
4113 struct target_siginfo info;
4114 struct target_ucontext uc;
4115} rt_sigframe;
4116
4117static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004118get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004119{
4120 abi_ulong sp;
4121
4122 /* Default to using normal stack */
4123 sp = env->regs[15];
4124
4125 /* This is the X/Open sanctioned signal stack switching. */
4126 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4127 if (!sas_ss_flags(sp)) {
4128 sp = target_sigaltstack_used.ss_sp +
4129 target_sigaltstack_used.ss_size;
4130 }
4131 }
4132
4133 /* This is the legacy signal stack switching. */
4134 else if (/* FIXME !user_mode(regs) */ 0 &&
4135 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4136 ka->sa_restorer) {
4137 sp = (abi_ulong) ka->sa_restorer;
4138 }
4139
4140 return (sp - frame_size) & -8ul;
4141}
4142
Andreas Färber05390242012-02-25 03:37:53 +01004143static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004144{
4145 int i;
4146 //save_access_regs(current->thread.acrs); FIXME
4147
4148 /* Copy a 'clean' PSW mask to the user to avoid leaking
4149 information about whether PER is currently on. */
4150 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4151 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4152 for (i = 0; i < 16; i++) {
4153 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4154 }
4155 for (i = 0; i < 16; i++) {
4156 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4157 }
4158 /*
4159 * We have to store the fp registers to current->thread.fp_regs
4160 * to merge them with the emulated registers.
4161 */
4162 //save_fp_regs(&current->thread.fp_regs); FIXME
4163 for (i = 0; i < 16; i++) {
4164 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4165 }
4166}
4167
4168static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004169 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004170{
4171 sigframe *frame;
4172 abi_ulong frame_addr;
4173
4174 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4175 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4176 (unsigned long long)frame_addr);
4177 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4178 goto give_sigsegv;
4179 }
4180
4181 qemu_log("%s: 1\n", __FUNCTION__);
4182 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
4183 goto give_sigsegv;
4184 }
4185
4186 save_sigregs(env, &frame->sregs);
4187
4188 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4189 (abi_ulong *)&frame->sc.sregs);
4190
4191 /* Set up to return from userspace. If provided, use a stub
4192 already in userspace. */
4193 if (ka->sa_flags & TARGET_SA_RESTORER) {
4194 env->regs[14] = (unsigned long)
4195 ka->sa_restorer | PSW_ADDR_AMODE;
4196 } else {
4197 env->regs[14] = (unsigned long)
4198 frame->retcode | PSW_ADDR_AMODE;
4199 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4200 (uint16_t *)(frame->retcode)))
4201 goto give_sigsegv;
4202 }
4203
4204 /* Set up backchain. */
4205 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4206 goto give_sigsegv;
4207 }
4208
4209 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004210 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004211 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4212
4213 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004214 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004215
4216 /* We forgot to include these in the sigcontext.
4217 To avoid breaking binary compatibility, they are passed as args. */
4218 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4219 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4220
4221 /* Place signal number on stack to allow backtrace from handler. */
4222 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4223 goto give_sigsegv;
4224 }
4225 unlock_user_struct(frame, frame_addr, 1);
4226 return;
4227
4228give_sigsegv:
4229 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4230 unlock_user_struct(frame, frame_addr, 1);
4231 force_sig(TARGET_SIGSEGV);
4232}
4233
4234static void setup_rt_frame(int sig, struct target_sigaction *ka,
4235 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004236 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004237{
4238 int i;
4239 rt_sigframe *frame;
4240 abi_ulong frame_addr;
4241
4242 frame_addr = get_sigframe(ka, env, sizeof *frame);
4243 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4244 (unsigned long long)frame_addr);
4245 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4246 goto give_sigsegv;
4247 }
4248
4249 qemu_log("%s: 1\n", __FUNCTION__);
4250 if (copy_siginfo_to_user(&frame->info, info)) {
4251 goto give_sigsegv;
4252 }
4253
4254 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004255 __put_user(0, &frame->uc.tuc_flags);
4256 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4257 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004258 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004259 &frame->uc.tuc_stack.ss_flags);
4260 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4261 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004262 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4263 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004264 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004265 }
4266
4267 /* Set up to return from userspace. If provided, use a stub
4268 already in userspace. */
4269 if (ka->sa_flags & TARGET_SA_RESTORER) {
4270 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4271 } else {
4272 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4273 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4274 (uint16_t *)(frame->retcode))) {
4275 goto give_sigsegv;
4276 }
4277 }
4278
4279 /* Set up backchain. */
4280 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4281 goto give_sigsegv;
4282 }
4283
4284 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004285 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004286 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4287
4288 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004289 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4290 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004291 return;
4292
4293give_sigsegv:
4294 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4295 unlock_user_struct(frame, frame_addr, 1);
4296 force_sig(TARGET_SIGSEGV);
4297}
4298
4299static int
Andreas Färber05390242012-02-25 03:37:53 +01004300restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004301{
4302 int err = 0;
4303 int i;
4304
4305 for (i = 0; i < 16; i++) {
4306 err |= __get_user(env->regs[i], &sc->regs.gprs[i]);
4307 }
4308
4309 err |= __get_user(env->psw.mask, &sc->regs.psw.mask);
4310 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4311 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4312 (unsigned long long)env->psw.addr);
4313 err |= __get_user(env->psw.addr, &sc->regs.psw.addr);
4314 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4315
4316 for (i = 0; i < 16; i++) {
4317 err |= __get_user(env->aregs[i], &sc->regs.acrs[i]);
4318 }
4319 for (i = 0; i < 16; i++) {
4320 err |= __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
4321 }
4322
4323 return err;
4324}
4325
Andreas Färber05390242012-02-25 03:37:53 +01004326long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004327{
4328 sigframe *frame;
4329 abi_ulong frame_addr = env->regs[15];
4330 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4331 (unsigned long long)frame_addr);
4332 target_sigset_t target_set;
4333 sigset_t set;
4334
4335 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4336 goto badframe;
4337 }
4338 if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
4339 goto badframe;
4340 }
4341
4342 target_to_host_sigset_internal(&set, &target_set);
4343 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4344
4345 if (restore_sigregs(env, &frame->sregs)) {
4346 goto badframe;
4347 }
4348
4349 unlock_user_struct(frame, frame_addr, 0);
4350 return env->regs[2];
4351
4352badframe:
4353 unlock_user_struct(frame, frame_addr, 0);
4354 force_sig(TARGET_SIGSEGV);
4355 return 0;
4356}
4357
Andreas Färber05390242012-02-25 03:37:53 +01004358long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004359{
4360 rt_sigframe *frame;
4361 abi_ulong frame_addr = env->regs[15];
4362 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4363 (unsigned long long)frame_addr);
4364 sigset_t set;
4365
4366 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4367 goto badframe;
4368 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004369 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004370
4371 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4372
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004373 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004374 goto badframe;
4375 }
4376
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004377 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004378 get_sp_from_cpustate(env)) == -EFAULT) {
4379 goto badframe;
4380 }
4381 unlock_user_struct(frame, frame_addr, 0);
4382 return env->regs[2];
4383
4384badframe:
4385 unlock_user_struct(frame, frame_addr, 0);
4386 force_sig(TARGET_SIGSEGV);
4387 return 0;
4388}
4389
Nathan Froydbcd49332009-05-12 19:13:18 -07004390#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4391
4392/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4393 the signal handling is different enough that we haven't implemented
4394 support for PPC64 yet. Hence the restriction above.
4395
4396 There are various #if'd blocks for code for TARGET_PPC64. These
4397 blocks should go away so that we can successfully run 32-bit and
4398 64-bit binaries on a QEMU configured for PPC64. */
4399
4400/* Size of dummy stack frame allocated when calling signal handler.
4401 See arch/powerpc/include/asm/ptrace.h. */
4402#if defined(TARGET_PPC64)
4403#define SIGNAL_FRAMESIZE 128
4404#else
4405#define SIGNAL_FRAMESIZE 64
4406#endif
4407
4408/* See arch/powerpc/include/asm/sigcontext.h. */
4409struct target_sigcontext {
4410 target_ulong _unused[4];
4411 int32_t signal;
4412#if defined(TARGET_PPC64)
4413 int32_t pad0;
4414#endif
4415 target_ulong handler;
4416 target_ulong oldmask;
4417 target_ulong regs; /* struct pt_regs __user * */
4418 /* TODO: PPC64 includes extra bits here. */
4419};
4420
4421/* Indices for target_mcontext.mc_gregs, below.
4422 See arch/powerpc/include/asm/ptrace.h for details. */
4423enum {
4424 TARGET_PT_R0 = 0,
4425 TARGET_PT_R1 = 1,
4426 TARGET_PT_R2 = 2,
4427 TARGET_PT_R3 = 3,
4428 TARGET_PT_R4 = 4,
4429 TARGET_PT_R5 = 5,
4430 TARGET_PT_R6 = 6,
4431 TARGET_PT_R7 = 7,
4432 TARGET_PT_R8 = 8,
4433 TARGET_PT_R9 = 9,
4434 TARGET_PT_R10 = 10,
4435 TARGET_PT_R11 = 11,
4436 TARGET_PT_R12 = 12,
4437 TARGET_PT_R13 = 13,
4438 TARGET_PT_R14 = 14,
4439 TARGET_PT_R15 = 15,
4440 TARGET_PT_R16 = 16,
4441 TARGET_PT_R17 = 17,
4442 TARGET_PT_R18 = 18,
4443 TARGET_PT_R19 = 19,
4444 TARGET_PT_R20 = 20,
4445 TARGET_PT_R21 = 21,
4446 TARGET_PT_R22 = 22,
4447 TARGET_PT_R23 = 23,
4448 TARGET_PT_R24 = 24,
4449 TARGET_PT_R25 = 25,
4450 TARGET_PT_R26 = 26,
4451 TARGET_PT_R27 = 27,
4452 TARGET_PT_R28 = 28,
4453 TARGET_PT_R29 = 29,
4454 TARGET_PT_R30 = 30,
4455 TARGET_PT_R31 = 31,
4456 TARGET_PT_NIP = 32,
4457 TARGET_PT_MSR = 33,
4458 TARGET_PT_ORIG_R3 = 34,
4459 TARGET_PT_CTR = 35,
4460 TARGET_PT_LNK = 36,
4461 TARGET_PT_XER = 37,
4462 TARGET_PT_CCR = 38,
4463 /* Yes, there are two registers with #39. One is 64-bit only. */
4464 TARGET_PT_MQ = 39,
4465 TARGET_PT_SOFTE = 39,
4466 TARGET_PT_TRAP = 40,
4467 TARGET_PT_DAR = 41,
4468 TARGET_PT_DSISR = 42,
4469 TARGET_PT_RESULT = 43,
4470 TARGET_PT_REGS_COUNT = 44
4471};
4472
4473/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4474 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4475struct target_mcontext {
4476 target_ulong mc_gregs[48];
4477 /* Includes fpscr. */
4478 uint64_t mc_fregs[33];
4479 target_ulong mc_pad[2];
4480 /* We need to handle Altivec and SPE at the same time, which no
4481 kernel needs to do. Fortunately, the kernel defines this bit to
4482 be Altivec-register-large all the time, rather than trying to
4483 twiddle it based on the specific platform. */
4484 union {
4485 /* SPE vector registers. One extra for SPEFSCR. */
4486 uint32_t spe[33];
4487 /* Altivec vector registers. The packing of VSCR and VRSAVE
4488 varies depending on whether we're PPC64 or not: PPC64 splits
4489 them apart; PPC32 stuffs them together. */
4490#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004491#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004492#else
malc3efa9a62009-07-18 13:10:12 +04004493#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004494#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004495 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004496#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004497 } mc_vregs __attribute__((__aligned__(16)));
4498};
4499
4500struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004501 target_ulong tuc_flags;
4502 target_ulong tuc_link; /* struct ucontext __user * */
4503 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004504#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004505 int32_t tuc_pad[7];
4506 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004507 points to uc_mcontext field */
4508#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004509 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004510#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004511 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004512 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004513#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004514 int32_t tuc_maskext[30];
4515 int32_t tuc_pad2[3];
4516 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004517#endif
4518};
4519
4520/* See arch/powerpc/kernel/signal_32.c. */
4521struct target_sigframe {
4522 struct target_sigcontext sctx;
4523 struct target_mcontext mctx;
4524 int32_t abigap[56];
4525};
4526
4527struct target_rt_sigframe {
4528 struct target_siginfo info;
4529 struct target_ucontext uc;
4530 int32_t abigap[56];
4531};
4532
4533/* We use the mc_pad field for the signal return trampoline. */
4534#define tramp mc_pad
4535
4536/* See arch/powerpc/kernel/signal.c. */
4537static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004538 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004539 int frame_size)
4540{
4541 target_ulong oldsp, newsp;
4542
4543 oldsp = env->gpr[1];
4544
4545 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004546 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004547 oldsp = (target_sigaltstack_used.ss_sp
4548 + target_sigaltstack_used.ss_size);
4549 }
4550
4551 newsp = (oldsp - frame_size) & ~0xFUL;
4552
4553 return newsp;
4554}
4555
Andreas Färber05390242012-02-25 03:37:53 +01004556static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004557 int sigret)
4558{
4559 target_ulong msr = env->msr;
4560 int i;
4561 target_ulong ccr = 0;
4562
4563 /* In general, the kernel attempts to be intelligent about what it
4564 needs to save for Altivec/FP/SPE registers. We don't care that
4565 much, so we just go ahead and save everything. */
4566
4567 /* Save general registers. */
4568 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4569 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4570 return 1;
4571 }
4572 }
4573 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4574 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4575 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4576 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4577 return 1;
4578
4579 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4580 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4581 }
4582 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4583 return 1;
4584
4585 /* Save Altivec registers if necessary. */
4586 if (env->insns_flags & PPC_ALTIVEC) {
4587 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004588 ppc_avr_t *avr = &env->avr[i];
4589 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004590
4591 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4592 __put_user(avr->u64[1], &vreg->u64[1])) {
4593 return 1;
4594 }
4595 }
4596 /* Set MSR_VR in the saved MSR value to indicate that
4597 frame->mc_vregs contains valid data. */
4598 msr |= MSR_VR;
4599 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4600 &frame->mc_vregs.altivec[32].u32[3]))
4601 return 1;
4602 }
4603
4604 /* Save floating point registers. */
4605 if (env->insns_flags & PPC_FLOAT) {
4606 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4607 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4608 return 1;
4609 }
4610 }
4611 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4612 return 1;
4613 }
4614
4615 /* Save SPE registers. The kernel only saves the high half. */
4616 if (env->insns_flags & PPC_SPE) {
4617#if defined(TARGET_PPC64)
4618 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4619 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4620 return 1;
4621 }
4622 }
4623#else
4624 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4625 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4626 return 1;
4627 }
4628 }
4629#endif
4630 /* Set MSR_SPE in the saved MSR value to indicate that
4631 frame->mc_vregs contains valid data. */
4632 msr |= MSR_SPE;
4633 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4634 return 1;
4635 }
4636
4637 /* Store MSR. */
4638 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4639 return 1;
4640
4641 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4642 if (sigret) {
4643 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4644 __put_user(0x44000002UL, &frame->tramp[1])) {
4645 return 1;
4646 }
4647 }
4648
4649 return 0;
4650}
4651
Andreas Färber05390242012-02-25 03:37:53 +01004652static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004653 struct target_mcontext *frame, int sig)
4654{
4655 target_ulong save_r2 = 0;
4656 target_ulong msr;
4657 target_ulong ccr;
4658
4659 int i;
4660
4661 if (!sig) {
4662 save_r2 = env->gpr[2];
4663 }
4664
4665 /* Restore general registers. */
4666 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4667 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4668 return 1;
4669 }
4670 }
4671 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4672 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4673 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4674 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4675 return 1;
4676 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4677 return 1;
4678
4679 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4680 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4681 }
4682
4683 if (!sig) {
4684 env->gpr[2] = save_r2;
4685 }
4686 /* Restore MSR. */
4687 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4688 return 1;
4689
4690 /* If doing signal return, restore the previous little-endian mode. */
4691 if (sig)
4692 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4693
4694 /* Restore Altivec registers if necessary. */
4695 if (env->insns_flags & PPC_ALTIVEC) {
4696 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004697 ppc_avr_t *avr = &env->avr[i];
4698 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004699
4700 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4701 __get_user(avr->u64[1], &vreg->u64[1])) {
4702 return 1;
4703 }
4704 }
4705 /* Set MSR_VEC in the saved MSR value to indicate that
4706 frame->mc_vregs contains valid data. */
4707 if (__get_user(env->spr[SPR_VRSAVE],
4708 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4709 return 1;
4710 }
4711
4712 /* Restore floating point registers. */
4713 if (env->insns_flags & PPC_FLOAT) {
4714 uint64_t fpscr;
4715 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4716 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4717 return 1;
4718 }
4719 }
4720 if (__get_user(fpscr, &frame->mc_fregs[32]))
4721 return 1;
4722 env->fpscr = (uint32_t) fpscr;
4723 }
4724
4725 /* Save SPE registers. The kernel only saves the high half. */
4726 if (env->insns_flags & PPC_SPE) {
4727#if defined(TARGET_PPC64)
4728 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4729 uint32_t hi;
4730
4731 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4732 return 1;
4733 }
4734 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4735 }
4736#else
4737 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4738 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4739 return 1;
4740 }
4741 }
4742#endif
4743 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4744 return 1;
4745 }
4746
4747 return 0;
4748}
4749
4750static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004751 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004752{
4753 struct target_sigframe *frame;
4754 struct target_sigcontext *sc;
4755 target_ulong frame_addr, newsp;
4756 int err = 0;
4757 int signal;
4758
4759 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4760 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4761 goto sigsegv;
4762 sc = &frame->sctx;
4763
4764 signal = current_exec_domain_sig(sig);
4765
Samuel Seaybeb526b2013-01-02 10:53:46 +00004766 err |= __put_user(ka->_sa_handler, &sc->handler);
Nathan Froydbcd49332009-05-12 19:13:18 -07004767 err |= __put_user(set->sig[0], &sc->oldmask);
4768#if defined(TARGET_PPC64)
4769 err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
4770#else
4771 err |= __put_user(set->sig[1], &sc->_unused[3]);
4772#endif
4773 err |= __put_user(h2g(&frame->mctx), &sc->regs);
4774 err |= __put_user(sig, &sc->signal);
4775
4776 /* Save user regs. */
4777 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4778
4779 /* The kernel checks for the presence of a VDSO here. We don't
4780 emulate a vdso, so use a sigreturn system call. */
4781 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4782
4783 /* Turn off all fp exceptions. */
4784 env->fpscr = 0;
4785
4786 /* Create a stack frame for the caller of the handler. */
4787 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004788 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004789
4790 if (err)
4791 goto sigsegv;
4792
4793 /* Set up registers for signal handler. */
4794 env->gpr[1] = newsp;
4795 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004796 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004797 env->nip = (target_ulong) ka->_sa_handler;
4798 /* Signal handlers are entered in big-endian mode. */
4799 env->msr &= ~MSR_LE;
4800
4801 unlock_user_struct(frame, frame_addr, 1);
4802 return;
4803
4804sigsegv:
4805 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004806 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004807 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004808}
4809
4810static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004811 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004812 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004813{
4814 struct target_rt_sigframe *rt_sf;
4815 struct target_mcontext *frame;
4816 target_ulong rt_sf_addr, newsp = 0;
4817 int i, err = 0;
4818 int signal;
4819
4820 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4821 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4822 goto sigsegv;
4823
4824 signal = current_exec_domain_sig(sig);
4825
4826 err |= copy_siginfo_to_user(&rt_sf->info, info);
4827
Aurelien Jarno60e99242010-03-29 02:12:51 +02004828 err |= __put_user(0, &rt_sf->uc.tuc_flags);
4829 err |= __put_user(0, &rt_sf->uc.tuc_link);
Nathan Froydbcd49332009-05-12 19:13:18 -07004830 err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004831 &rt_sf->uc.tuc_stack.ss_sp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004832 err |= __put_user(sas_ss_flags(env->gpr[1]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02004833 &rt_sf->uc.tuc_stack.ss_flags);
Nathan Froydbcd49332009-05-12 19:13:18 -07004834 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004835 &rt_sf->uc.tuc_stack.ss_size);
4836 err |= __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4837 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004838 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004839 err |= __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004840 }
4841
Aurelien Jarno60e99242010-03-29 02:12:51 +02004842 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004843 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4844
4845 /* The kernel checks for the presence of a VDSO here. We don't
4846 emulate a vdso, so use a sigreturn system call. */
4847 env->lr = (target_ulong) h2g(frame->tramp);
4848
4849 /* Turn off all fp exceptions. */
4850 env->fpscr = 0;
4851
4852 /* Create a stack frame for the caller of the handler. */
4853 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
4854 err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
4855
4856 if (err)
4857 goto sigsegv;
4858
4859 /* Set up registers for signal handler. */
4860 env->gpr[1] = newsp;
4861 env->gpr[3] = (target_ulong) signal;
4862 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4863 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4864 env->gpr[6] = (target_ulong) h2g(rt_sf);
4865 env->nip = (target_ulong) ka->_sa_handler;
4866 /* Signal handlers are entered in big-endian mode. */
4867 env->msr &= ~MSR_LE;
4868
4869 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4870 return;
4871
4872sigsegv:
4873 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004874 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004875 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004876
4877}
4878
Andreas Färber05390242012-02-25 03:37:53 +01004879long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004880{
4881 struct target_sigcontext *sc = NULL;
4882 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004883 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004884 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004885 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004886
4887 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4888 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4889 goto sigsegv;
4890
4891#if defined(TARGET_PPC64)
4892 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4893#else
4894 if(__get_user(set.sig[0], &sc->oldmask) ||
4895 __get_user(set.sig[1], &sc->_unused[3]))
4896 goto sigsegv;
4897#endif
4898 target_to_host_sigset_internal(&blocked, &set);
4899 sigprocmask(SIG_SETMASK, &blocked, NULL);
4900
4901 if (__get_user(sr_addr, &sc->regs))
4902 goto sigsegv;
4903 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4904 goto sigsegv;
4905 if (restore_user_regs(env, sr, 1))
4906 goto sigsegv;
4907
4908 unlock_user_struct(sr, sr_addr, 1);
4909 unlock_user_struct(sc, sc_addr, 1);
4910 return -TARGET_QEMU_ESIGRETURN;
4911
4912sigsegv:
4913 unlock_user_struct(sr, sr_addr, 1);
4914 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004915 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004916 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004917 return 0;
4918}
4919
4920/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004921static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004922{
4923 struct target_mcontext *mcp;
4924 target_ulong mcp_addr;
4925 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004926 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004927
Aurelien Jarno60e99242010-03-29 02:12:51 +02004928 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004929 sizeof (set)))
4930 return 1;
4931
4932#if defined(TARGET_PPC64)
4933 fprintf (stderr, "do_setcontext: not implemented\n");
4934 return 0;
4935#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004936 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004937 return 1;
4938
4939 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4940 return 1;
4941
4942 target_to_host_sigset_internal(&blocked, &set);
4943 sigprocmask(SIG_SETMASK, &blocked, NULL);
4944 if (restore_user_regs(env, mcp, sig))
4945 goto sigsegv;
4946
4947 unlock_user_struct(mcp, mcp_addr, 1);
4948 return 0;
4949
4950sigsegv:
4951 unlock_user_struct(mcp, mcp_addr, 1);
4952 return 1;
4953#endif
4954}
4955
Andreas Färber05390242012-02-25 03:37:53 +01004956long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004957{
4958 struct target_rt_sigframe *rt_sf = NULL;
4959 target_ulong rt_sf_addr;
4960
4961 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4962 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4963 goto sigsegv;
4964
4965 if (do_setcontext(&rt_sf->uc, env, 1))
4966 goto sigsegv;
4967
4968 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004969 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004970 0, env->gpr[1]);
4971
4972 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4973 return -TARGET_QEMU_ESIGRETURN;
4974
4975sigsegv:
4976 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004977 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004978 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004979 return 0;
4980}
4981
Laurent Vivier492a8742009-08-03 16:12:17 +02004982#elif defined(TARGET_M68K)
4983
4984struct target_sigcontext {
4985 abi_ulong sc_mask;
4986 abi_ulong sc_usp;
4987 abi_ulong sc_d0;
4988 abi_ulong sc_d1;
4989 abi_ulong sc_a0;
4990 abi_ulong sc_a1;
4991 unsigned short sc_sr;
4992 abi_ulong sc_pc;
4993};
4994
4995struct target_sigframe
4996{
4997 abi_ulong pretcode;
4998 int sig;
4999 int code;
5000 abi_ulong psc;
5001 char retcode[8];
5002 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5003 struct target_sigcontext sc;
5004};
Laurent Vivier71811552009-08-03 16:12:18 +02005005
Anthony Liguoric227f092009-10-01 16:12:16 -05005006typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005007#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005008typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005009
5010typedef struct target_fpregset {
5011 int f_fpcntl[3];
5012 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005013} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005014
5015struct target_mcontext {
5016 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005017 target_gregset_t gregs;
5018 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005019};
5020
5021#define TARGET_MCONTEXT_VERSION 2
5022
5023struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005024 abi_ulong tuc_flags;
5025 abi_ulong tuc_link;
5026 target_stack_t tuc_stack;
5027 struct target_mcontext tuc_mcontext;
5028 abi_long tuc_filler[80];
5029 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005030};
5031
5032struct target_rt_sigframe
5033{
5034 abi_ulong pretcode;
5035 int sig;
5036 abi_ulong pinfo;
5037 abi_ulong puc;
5038 char retcode[8];
5039 struct target_siginfo info;
5040 struct target_ucontext uc;
5041};
Laurent Vivier492a8742009-08-03 16:12:17 +02005042
5043static int
Andreas Färber05390242012-02-25 03:37:53 +01005044setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
5045 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005046{
5047 int err = 0;
5048
5049 err |= __put_user(mask, &sc->sc_mask);
5050 err |= __put_user(env->aregs[7], &sc->sc_usp);
5051 err |= __put_user(env->dregs[0], &sc->sc_d0);
5052 err |= __put_user(env->dregs[1], &sc->sc_d1);
5053 err |= __put_user(env->aregs[0], &sc->sc_a0);
5054 err |= __put_user(env->aregs[1], &sc->sc_a1);
5055 err |= __put_user(env->sr, &sc->sc_sr);
5056 err |= __put_user(env->pc, &sc->sc_pc);
5057
5058 return err;
5059}
5060
5061static int
Andreas Färber05390242012-02-25 03:37:53 +01005062restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005063{
5064 int err = 0;
5065 int temp;
5066
5067 err |= __get_user(env->aregs[7], &sc->sc_usp);
5068 err |= __get_user(env->dregs[1], &sc->sc_d1);
5069 err |= __get_user(env->aregs[0], &sc->sc_a0);
5070 err |= __get_user(env->aregs[1], &sc->sc_a1);
5071 err |= __get_user(env->pc, &sc->sc_pc);
5072 err |= __get_user(temp, &sc->sc_sr);
5073 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5074
5075 *pd0 = tswapl(sc->sc_d0);
5076
5077 return err;
5078}
5079
5080/*
5081 * Determine which stack to use..
5082 */
5083static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005084get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5085 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005086{
5087 unsigned long sp;
5088
5089 sp = regs->aregs[7];
5090
5091 /* This is the X/Open sanctioned signal stack switching. */
5092 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5093 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5094 }
5095
5096 return ((sp - frame_size) & -8UL);
5097}
5098
5099static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005100 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005101{
5102 struct target_sigframe *frame;
5103 abi_ulong frame_addr;
5104 abi_ulong retcode_addr;
5105 abi_ulong sc_addr;
5106 int err = 0;
5107 int i;
5108
5109 frame_addr = get_sigframe(ka, env, sizeof *frame);
5110 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5111 goto give_sigsegv;
5112
5113 err |= __put_user(sig, &frame->sig);
5114
5115 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
5116 err |= __put_user(sc_addr, &frame->psc);
5117
5118 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
5119 if (err)
5120 goto give_sigsegv;
5121
5122 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5123 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
5124 goto give_sigsegv;
5125 }
5126
5127 /* Set up to return from userspace. */
5128
5129 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5130 err |= __put_user(retcode_addr, &frame->pretcode);
5131
5132 /* moveq #,d0; trap #0 */
5133
5134 err |= __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
5135 (long *)(frame->retcode));
5136
5137 if (err)
5138 goto give_sigsegv;
5139
5140 /* Set up to return from userspace */
5141
5142 env->aregs[7] = frame_addr;
5143 env->pc = ka->_sa_handler;
5144
5145 unlock_user_struct(frame, frame_addr, 1);
5146 return;
5147
5148give_sigsegv:
5149 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005150 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005151}
5152
Laurent Vivier71811552009-08-03 16:12:18 +02005153static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005154 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005155{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005156 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005157 int err;
5158
Aurelien Jarno60e99242010-03-29 02:12:51 +02005159 err = __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005160 err |= __put_user(env->dregs[0], &gregs[0]);
5161 err |= __put_user(env->dregs[1], &gregs[1]);
5162 err |= __put_user(env->dregs[2], &gregs[2]);
5163 err |= __put_user(env->dregs[3], &gregs[3]);
5164 err |= __put_user(env->dregs[4], &gregs[4]);
5165 err |= __put_user(env->dregs[5], &gregs[5]);
5166 err |= __put_user(env->dregs[6], &gregs[6]);
5167 err |= __put_user(env->dregs[7], &gregs[7]);
5168 err |= __put_user(env->aregs[0], &gregs[8]);
5169 err |= __put_user(env->aregs[1], &gregs[9]);
5170 err |= __put_user(env->aregs[2], &gregs[10]);
5171 err |= __put_user(env->aregs[3], &gregs[11]);
5172 err |= __put_user(env->aregs[4], &gregs[12]);
5173 err |= __put_user(env->aregs[5], &gregs[13]);
5174 err |= __put_user(env->aregs[6], &gregs[14]);
5175 err |= __put_user(env->aregs[7], &gregs[15]);
5176 err |= __put_user(env->pc, &gregs[16]);
5177 err |= __put_user(env->sr, &gregs[17]);
5178
5179 return err;
5180}
5181
Andreas Färber05390242012-02-25 03:37:53 +01005182static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005183 struct target_ucontext *uc,
5184 int *pd0)
5185{
5186 int temp;
5187 int err;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005188 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005189
Aurelien Jarno60e99242010-03-29 02:12:51 +02005190 err = __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005191 if (temp != TARGET_MCONTEXT_VERSION)
5192 goto badframe;
5193
5194 /* restore passed registers */
5195 err |= __get_user(env->dregs[0], &gregs[0]);
5196 err |= __get_user(env->dregs[1], &gregs[1]);
5197 err |= __get_user(env->dregs[2], &gregs[2]);
5198 err |= __get_user(env->dregs[3], &gregs[3]);
5199 err |= __get_user(env->dregs[4], &gregs[4]);
5200 err |= __get_user(env->dregs[5], &gregs[5]);
5201 err |= __get_user(env->dregs[6], &gregs[6]);
5202 err |= __get_user(env->dregs[7], &gregs[7]);
5203 err |= __get_user(env->aregs[0], &gregs[8]);
5204 err |= __get_user(env->aregs[1], &gregs[9]);
5205 err |= __get_user(env->aregs[2], &gregs[10]);
5206 err |= __get_user(env->aregs[3], &gregs[11]);
5207 err |= __get_user(env->aregs[4], &gregs[12]);
5208 err |= __get_user(env->aregs[5], &gregs[13]);
5209 err |= __get_user(env->aregs[6], &gregs[14]);
5210 err |= __get_user(env->aregs[7], &gregs[15]);
5211 err |= __get_user(env->pc, &gregs[16]);
5212 err |= __get_user(temp, &gregs[17]);
5213 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5214
5215 *pd0 = env->dregs[0];
5216 return err;
5217
5218badframe:
5219 return 1;
5220}
5221
Laurent Vivier492a8742009-08-03 16:12:17 +02005222static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005223 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005224 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005225{
Laurent Vivier71811552009-08-03 16:12:18 +02005226 struct target_rt_sigframe *frame;
5227 abi_ulong frame_addr;
5228 abi_ulong retcode_addr;
5229 abi_ulong info_addr;
5230 abi_ulong uc_addr;
5231 int err = 0;
5232 int i;
5233
5234 frame_addr = get_sigframe(ka, env, sizeof *frame);
5235 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5236 goto give_sigsegv;
5237
5238 err |= __put_user(sig, &frame->sig);
5239
5240 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
5241 err |= __put_user(info_addr, &frame->pinfo);
5242
5243 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
5244 err |= __put_user(uc_addr, &frame->puc);
5245
5246 err |= copy_siginfo_to_user(&frame->info, info);
5247
5248 /* Create the ucontext */
5249
Aurelien Jarno60e99242010-03-29 02:12:51 +02005250 err |= __put_user(0, &frame->uc.tuc_flags);
5251 err |= __put_user(0, &frame->uc.tuc_link);
Laurent Vivier71811552009-08-03 16:12:18 +02005252 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005253 &frame->uc.tuc_stack.ss_sp);
Laurent Vivier71811552009-08-03 16:12:18 +02005254 err |= __put_user(sas_ss_flags(env->aregs[7]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005255 &frame->uc.tuc_stack.ss_flags);
Laurent Vivier71811552009-08-03 16:12:18 +02005256 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005257 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005258 err |= target_rt_setup_ucontext(&frame->uc, env);
5259
5260 if (err)
5261 goto give_sigsegv;
5262
5263 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005264 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005265 goto give_sigsegv;
5266 }
5267
5268 /* Set up to return from userspace. */
5269
5270 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5271 err |= __put_user(retcode_addr, &frame->pretcode);
5272
5273 /* moveq #,d0; notb d0; trap #0 */
5274
5275 err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5276 (long *)(frame->retcode + 0));
5277 err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
5278
5279 if (err)
5280 goto give_sigsegv;
5281
5282 /* Set up to return from userspace */
5283
5284 env->aregs[7] = frame_addr;
5285 env->pc = ka->_sa_handler;
5286
5287 unlock_user_struct(frame, frame_addr, 1);
5288 return;
5289
5290give_sigsegv:
5291 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005292 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005293}
5294
Andreas Färber05390242012-02-25 03:37:53 +01005295long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005296{
5297 struct target_sigframe *frame;
5298 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005299 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005300 sigset_t set;
5301 int d0, i;
5302
5303 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5304 goto badframe;
5305
5306 /* set blocked signals */
5307
5308 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
5309 goto badframe;
5310
5311 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5312 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
5313 goto badframe;
5314 }
5315
5316 target_to_host_sigset_internal(&set, &target_set);
5317 sigprocmask(SIG_SETMASK, &set, NULL);
5318
5319 /* restore registers */
5320
5321 if (restore_sigcontext(env, &frame->sc, &d0))
5322 goto badframe;
5323
5324 unlock_user_struct(frame, frame_addr, 0);
5325 return d0;
5326
5327badframe:
5328 unlock_user_struct(frame, frame_addr, 0);
5329 force_sig(TARGET_SIGSEGV);
5330 return 0;
5331}
5332
Andreas Färber05390242012-02-25 03:37:53 +01005333long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005334{
Laurent Vivier71811552009-08-03 16:12:18 +02005335 struct target_rt_sigframe *frame;
5336 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005337 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005338 sigset_t set;
5339 int d0;
5340
5341 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5342 goto badframe;
5343
5344 target_to_host_sigset_internal(&set, &target_set);
5345 sigprocmask(SIG_SETMASK, &set, NULL);
5346
5347 /* restore registers */
5348
5349 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5350 goto badframe;
5351
5352 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005353 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005354 0, get_sp_from_cpustate(env)) == -EFAULT)
5355 goto badframe;
5356
5357 unlock_user_struct(frame, frame_addr, 0);
5358 return d0;
5359
5360badframe:
5361 unlock_user_struct(frame, frame_addr, 0);
5362 force_sig(TARGET_SIGSEGV);
5363 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005364}
5365
Richard Henderson6049f4f2009-12-27 18:30:03 -08005366#elif defined(TARGET_ALPHA)
5367
5368struct target_sigcontext {
5369 abi_long sc_onstack;
5370 abi_long sc_mask;
5371 abi_long sc_pc;
5372 abi_long sc_ps;
5373 abi_long sc_regs[32];
5374 abi_long sc_ownedfp;
5375 abi_long sc_fpregs[32];
5376 abi_ulong sc_fpcr;
5377 abi_ulong sc_fp_control;
5378 abi_ulong sc_reserved1;
5379 abi_ulong sc_reserved2;
5380 abi_ulong sc_ssize;
5381 abi_ulong sc_sbase;
5382 abi_ulong sc_traparg_a0;
5383 abi_ulong sc_traparg_a1;
5384 abi_ulong sc_traparg_a2;
5385 abi_ulong sc_fp_trap_pc;
5386 abi_ulong sc_fp_trigger_sum;
5387 abi_ulong sc_fp_trigger_inst;
5388};
5389
5390struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005391 abi_ulong tuc_flags;
5392 abi_ulong tuc_link;
5393 abi_ulong tuc_osf_sigmask;
5394 target_stack_t tuc_stack;
5395 struct target_sigcontext tuc_mcontext;
5396 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005397};
5398
5399struct target_sigframe {
5400 struct target_sigcontext sc;
5401 unsigned int retcode[3];
5402};
5403
5404struct target_rt_sigframe {
5405 target_siginfo_t info;
5406 struct target_ucontext uc;
5407 unsigned int retcode[3];
5408};
5409
5410#define INSN_MOV_R30_R16 0x47fe0410
5411#define INSN_LDI_R0 0x201f0000
5412#define INSN_CALLSYS 0x00000083
5413
Andreas Färber05390242012-02-25 03:37:53 +01005414static int setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005415 abi_ulong frame_addr, target_sigset_t *set)
5416{
5417 int i, err = 0;
5418
5419 err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5420 err |= __put_user(set->sig[0], &sc->sc_mask);
5421 err |= __put_user(env->pc, &sc->sc_pc);
5422 err |= __put_user(8, &sc->sc_ps);
5423
5424 for (i = 0; i < 31; ++i) {
5425 err |= __put_user(env->ir[i], &sc->sc_regs[i]);
5426 }
5427 err |= __put_user(0, &sc->sc_regs[31]);
5428
5429 for (i = 0; i < 31; ++i) {
5430 err |= __put_user(env->fir[i], &sc->sc_fpregs[i]);
5431 }
5432 err |= __put_user(0, &sc->sc_fpregs[31]);
5433 err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
5434
5435 err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5436 err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5437 err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */
5438
5439 return err;
5440}
5441
Andreas Färber05390242012-02-25 03:37:53 +01005442static int restore_sigcontext(CPUAlphaState *env,
5443 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005444{
5445 uint64_t fpcr;
5446 int i, err = 0;
5447
5448 err |= __get_user(env->pc, &sc->sc_pc);
5449
5450 for (i = 0; i < 31; ++i) {
5451 err |= __get_user(env->ir[i], &sc->sc_regs[i]);
5452 }
5453 for (i = 0; i < 31; ++i) {
5454 err |= __get_user(env->fir[i], &sc->sc_fpregs[i]);
5455 }
5456
5457 err |= __get_user(fpcr, &sc->sc_fpcr);
5458 cpu_alpha_store_fpcr(env, fpcr);
5459
5460 return err;
5461}
5462
5463static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005464 CPUAlphaState *env,
5465 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005466{
5467 abi_ulong sp = env->ir[IR_SP];
5468
5469 /* This is the X/Open sanctioned signal stack switching. */
5470 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5471 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5472 }
5473 return (sp - framesize) & -32;
5474}
5475
5476static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005477 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005478{
5479 abi_ulong frame_addr, r26;
5480 struct target_sigframe *frame;
5481 int err = 0;
5482
5483 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5484 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5485 goto give_sigsegv;
5486 }
5487
5488 err |= setup_sigcontext(&frame->sc, env, frame_addr, set);
5489
5490 if (ka->sa_restorer) {
5491 r26 = ka->sa_restorer;
5492 } else {
5493 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5494 err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5495 &frame->retcode[1]);
5496 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5497 /* imb() */
5498 r26 = frame_addr;
5499 }
5500
5501 unlock_user_struct(frame, frame_addr, 1);
5502
5503 if (err) {
5504 give_sigsegv:
5505 if (sig == TARGET_SIGSEGV) {
5506 ka->_sa_handler = TARGET_SIG_DFL;
5507 }
5508 force_sig(TARGET_SIGSEGV);
5509 }
5510
5511 env->ir[IR_RA] = r26;
5512 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5513 env->ir[IR_A0] = sig;
5514 env->ir[IR_A1] = 0;
5515 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5516 env->ir[IR_SP] = frame_addr;
5517}
5518
5519static void setup_rt_frame(int sig, struct target_sigaction *ka,
5520 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005521 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005522{
5523 abi_ulong frame_addr, r26;
5524 struct target_rt_sigframe *frame;
5525 int i, err = 0;
5526
5527 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5528 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5529 goto give_sigsegv;
5530 }
5531
5532 err |= copy_siginfo_to_user(&frame->info, info);
5533
Aurelien Jarno60e99242010-03-29 02:12:51 +02005534 err |= __put_user(0, &frame->uc.tuc_flags);
5535 err |= __put_user(0, &frame->uc.tuc_link);
5536 err |= __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005537 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005538 &frame->uc.tuc_stack.ss_sp);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005539 err |= __put_user(sas_ss_flags(env->ir[IR_SP]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005540 &frame->uc.tuc_stack.ss_flags);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005541 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005542 &frame->uc.tuc_stack.ss_size);
5543 err |= setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005544 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005545 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005546 }
5547
5548 if (ka->sa_restorer) {
5549 r26 = ka->sa_restorer;
5550 } else {
5551 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5552 err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5553 &frame->retcode[1]);
5554 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5555 /* imb(); */
5556 r26 = frame_addr;
5557 }
5558
5559 if (err) {
5560 give_sigsegv:
5561 if (sig == TARGET_SIGSEGV) {
5562 ka->_sa_handler = TARGET_SIG_DFL;
5563 }
5564 force_sig(TARGET_SIGSEGV);
5565 }
5566
5567 env->ir[IR_RA] = r26;
5568 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5569 env->ir[IR_A0] = sig;
5570 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5571 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5572 env->ir[IR_SP] = frame_addr;
5573}
5574
Andreas Färber05390242012-02-25 03:37:53 +01005575long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005576{
5577 struct target_sigcontext *sc;
5578 abi_ulong sc_addr = env->ir[IR_A0];
5579 target_sigset_t target_set;
5580 sigset_t set;
5581
5582 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5583 goto badframe;
5584 }
5585
5586 target_sigemptyset(&target_set);
5587 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
5588 goto badframe;
5589 }
5590
5591 target_to_host_sigset_internal(&set, &target_set);
5592 sigprocmask(SIG_SETMASK, &set, NULL);
5593
5594 if (restore_sigcontext(env, sc)) {
5595 goto badframe;
5596 }
5597 unlock_user_struct(sc, sc_addr, 0);
5598 return env->ir[IR_V0];
5599
5600 badframe:
5601 unlock_user_struct(sc, sc_addr, 0);
5602 force_sig(TARGET_SIGSEGV);
5603}
5604
Andreas Färber05390242012-02-25 03:37:53 +01005605long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005606{
5607 abi_ulong frame_addr = env->ir[IR_A0];
5608 struct target_rt_sigframe *frame;
5609 sigset_t set;
5610
5611 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5612 goto badframe;
5613 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005614 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005615 sigprocmask(SIG_SETMASK, &set, NULL);
5616
Aurelien Jarno60e99242010-03-29 02:12:51 +02005617 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005618 goto badframe;
5619 }
5620 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005621 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005622 0, env->ir[IR_SP]) == -EFAULT) {
5623 goto badframe;
5624 }
5625
5626 unlock_user_struct(frame, frame_addr, 0);
5627 return env->ir[IR_V0];
5628
5629
5630 badframe:
5631 unlock_user_struct(frame, frame_addr, 0);
5632 force_sig(TARGET_SIGSEGV);
5633}
5634
bellardb346ff42003-06-15 20:05:50 +00005635#else
5636
pbrook624f7972008-05-31 16:11:38 +00005637static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005638 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005639{
5640 fprintf(stderr, "setup_frame: not implemented\n");
5641}
5642
pbrook624f7972008-05-31 16:11:38 +00005643static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005644 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005645 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005646{
5647 fprintf(stderr, "setup_rt_frame: not implemented\n");
5648}
5649
Andreas Färber9349b4f2012-03-14 01:38:32 +01005650long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005651{
5652 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005653 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005654}
5655
Andreas Färber9349b4f2012-03-14 01:38:32 +01005656long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005657{
5658 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005659 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005660}
5661
bellard66fb9762003-03-23 01:06:05 +00005662#endif
5663
Andreas Färber9349b4f2012-03-14 01:38:32 +01005664void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005665{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005666 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005667 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005668 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005669 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005670 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005671 struct emulated_sigtable *k;
5672 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005673 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00005674 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00005675
pbrook624f7972008-05-31 16:11:38 +00005676 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005677 return;
5678
pbrook624f7972008-05-31 16:11:38 +00005679 /* FIXME: This is not threadsafe. */
5680 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005681 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5682 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005683 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005684 k++;
bellard31e31b82003-02-18 22:55:36 +00005685 }
5686 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005687 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005688 return;
bellard66fb9762003-03-23 01:06:05 +00005689
bellard31e31b82003-02-18 22:55:36 +00005690 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005691#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005692 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005693#endif
5694 /* dequeue signal */
5695 q = k->first;
5696 k->first = q->next;
5697 if (!k->first)
5698 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005699
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005700 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005701 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005702 sa = NULL;
5703 handler = TARGET_SIG_IGN;
5704 } else {
5705 sa = &sigact_table[sig - 1];
5706 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005707 }
bellard66fb9762003-03-23 01:06:05 +00005708
bellard66fb9762003-03-23 01:06:05 +00005709 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005710 /* default handler : ignore some signal. The other are job control or fatal */
5711 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5712 kill(getpid(),SIGSTOP);
5713 } else if (sig != TARGET_SIGCHLD &&
5714 sig != TARGET_SIGURG &&
5715 sig != TARGET_SIGWINCH &&
5716 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005717 force_sig(sig);
5718 }
5719 } else if (handler == TARGET_SIG_IGN) {
5720 /* ignore sig */
5721 } else if (handler == TARGET_SIG_ERR) {
5722 force_sig(sig);
5723 } else {
bellard9de5e442003-03-23 16:49:39 +00005724 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005725 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005726 /* SA_NODEFER indicates that the current signal should not be
5727 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005728 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005729 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005730
bellard9de5e442003-03-23 16:49:39 +00005731 /* block signals in the handler using Linux */
5732 sigprocmask(SIG_BLOCK, &set, &old_set);
5733 /* save the previous blocked signal state to restore it at the
5734 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005735 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005736
bellardbc8a22c2003-03-30 21:02:40 +00005737 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005738#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005739 {
5740 CPUX86State *env = cpu_env;
5741 if (env->eflags & VM_MASK)
5742 save_v86_state(env);
5743 }
5744#endif
bellard9de5e442003-03-23 16:49:39 +00005745 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005746#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5747 /* These targets do not have traditional signals. */
5748 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5749#else
pbrook624f7972008-05-31 16:11:38 +00005750 if (sa->sa_flags & TARGET_SA_SIGINFO)
5751 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005752 else
pbrook624f7972008-05-31 16:11:38 +00005753 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005754#endif
pbrook624f7972008-05-31 16:11:38 +00005755 if (sa->sa_flags & TARGET_SA_RESETHAND)
5756 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005757 }
bellard66fb9762003-03-23 01:06:05 +00005758 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005759 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005760}