blob: 04638e2ead79722b9f5030effdf20ba26e64a1d1 [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
1236 for (i = 0; i < 32 * 2; i++) {
1237 __get_user(env->vfp.regs[i], &aux->fpsimd.vregs[i]);
1238 }
Will Newtone0ee1382014-01-04 22:15:48 +00001239 __get_user(fpsr, &aux->fpsimd.fpsr);
1240 vfp_set_fpsr(env, fpsr);
1241 __get_user(fpcr, &aux->fpsimd.fpcr);
1242 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001243
1244 return 0;
1245}
1246
1247static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1248{
1249 abi_ulong sp;
1250
1251 sp = env->xregs[31];
1252
1253 /*
1254 * This is the X/Open sanctioned signal stack switching.
1255 */
1256 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1257 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1258 }
1259
1260 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1261
1262 return sp;
1263}
1264
1265static void target_setup_frame(int usig, struct target_sigaction *ka,
1266 target_siginfo_t *info, target_sigset_t *set,
1267 CPUARMState *env)
1268{
1269 struct target_rt_sigframe *frame;
1270 abi_ulong frame_addr;
1271
1272 frame_addr = get_sigframe(ka, env);
1273 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1274 goto give_sigsegv;
1275 }
1276
1277 __put_user(0, &frame->uc.tuc_flags);
1278 __put_user(0, &frame->uc.tuc_link);
1279
1280 __put_user(target_sigaltstack_used.ss_sp,
1281 &frame->uc.tuc_stack.ss_sp);
1282 __put_user(sas_ss_flags(env->xregs[31]),
1283 &frame->uc.tuc_stack.ss_flags);
1284 __put_user(target_sigaltstack_used.ss_size,
1285 &frame->uc.tuc_stack.ss_size);
1286 target_setup_sigframe(frame, env, set);
1287 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1288 __put_user(0xd2801168, &frame->tramp[0]);
1289 __put_user(0xd4000001, &frame->tramp[1]);
1290 env->xregs[0] = usig;
1291 env->xregs[31] = frame_addr;
1292 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1293 env->pc = ka->_sa_handler;
1294 env->xregs[30] = env->xregs[31] +
1295 offsetof(struct target_rt_sigframe, tramp);
1296 if (info) {
1297 if (copy_siginfo_to_user(&frame->info, info)) {
1298 goto give_sigsegv;
1299 }
1300 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1301 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1302 }
1303
1304 unlock_user_struct(frame, frame_addr, 1);
1305 return;
1306
1307 give_sigsegv:
1308 unlock_user_struct(frame, frame_addr, 1);
1309 force_sig(TARGET_SIGSEGV);
1310}
1311
1312static void setup_rt_frame(int sig, struct target_sigaction *ka,
1313 target_siginfo_t *info, target_sigset_t *set,
1314 CPUARMState *env)
1315{
1316 target_setup_frame(sig, ka, info, set, env);
1317}
1318
1319static void setup_frame(int sig, struct target_sigaction *ka,
1320 target_sigset_t *set, CPUARMState *env)
1321{
1322 target_setup_frame(sig, ka, 0, set, env);
1323}
1324
1325long do_rt_sigreturn(CPUARMState *env)
1326{
1327 struct target_rt_sigframe *frame;
1328 abi_ulong frame_addr = env->xregs[31];
1329
1330 if (frame_addr & 15) {
1331 goto badframe;
1332 }
1333
1334 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1335 goto badframe;
1336 }
1337
1338 if (target_restore_sigframe(env, frame)) {
1339 goto badframe;
1340 }
1341
1342 if (do_sigaltstack(frame_addr +
1343 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1344 0, get_sp_from_cpustate(env)) == -EFAULT) {
1345 goto badframe;
1346 }
1347
1348 unlock_user_struct(frame, frame_addr, 0);
1349 return env->xregs[0];
1350
1351 badframe:
1352 unlock_user_struct(frame, frame_addr, 0);
1353 force_sig(TARGET_SIGSEGV);
1354 return 0;
1355}
1356
1357long do_sigreturn(CPUARMState *env)
1358{
1359 return do_rt_sigreturn(env);
1360}
1361
bellard43fff232003-07-09 19:31:39 +00001362#elif defined(TARGET_ARM)
1363
1364struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001365 abi_ulong trap_no;
1366 abi_ulong error_code;
1367 abi_ulong oldmask;
1368 abi_ulong arm_r0;
1369 abi_ulong arm_r1;
1370 abi_ulong arm_r2;
1371 abi_ulong arm_r3;
1372 abi_ulong arm_r4;
1373 abi_ulong arm_r5;
1374 abi_ulong arm_r6;
1375 abi_ulong arm_r7;
1376 abi_ulong arm_r8;
1377 abi_ulong arm_r9;
1378 abi_ulong arm_r10;
1379 abi_ulong arm_fp;
1380 abi_ulong arm_ip;
1381 abi_ulong arm_sp;
1382 abi_ulong arm_lr;
1383 abi_ulong arm_pc;
1384 abi_ulong arm_cpsr;
1385 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001386};
1387
pbrooka745ec62008-05-06 15:36:17 +00001388struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001389 abi_ulong tuc_flags;
1390 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001391 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001392 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001393 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001394};
1395
pbrooka745ec62008-05-06 15:36:17 +00001396struct target_ucontext_v2 {
1397 abi_ulong tuc_flags;
1398 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001399 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001400 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001401 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001402 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001403 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1404};
1405
Peter Maydell0d871bd2010-11-24 15:20:05 +00001406struct target_user_vfp {
1407 uint64_t fpregs[32];
1408 abi_ulong fpscr;
1409};
1410
1411struct target_user_vfp_exc {
1412 abi_ulong fpexc;
1413 abi_ulong fpinst;
1414 abi_ulong fpinst2;
1415};
1416
1417struct target_vfp_sigframe {
1418 abi_ulong magic;
1419 abi_ulong size;
1420 struct target_user_vfp ufp;
1421 struct target_user_vfp_exc ufp_exc;
1422} __attribute__((__aligned__(8)));
1423
Peter Maydell08e11252010-11-24 15:20:07 +00001424struct target_iwmmxt_sigframe {
1425 abi_ulong magic;
1426 abi_ulong size;
1427 uint64_t regs[16];
1428 /* Note that not all the coprocessor control registers are stored here */
1429 uint32_t wcssf;
1430 uint32_t wcasf;
1431 uint32_t wcgr0;
1432 uint32_t wcgr1;
1433 uint32_t wcgr2;
1434 uint32_t wcgr3;
1435} __attribute__((__aligned__(8)));
1436
Peter Maydell0d871bd2010-11-24 15:20:05 +00001437#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001438#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001439
pbrooka8c33202008-05-07 23:22:46 +00001440struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001441{
1442 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001443 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1444 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001445};
1446
pbrooka8c33202008-05-07 23:22:46 +00001447struct sigframe_v2
1448{
1449 struct target_ucontext_v2 uc;
1450 abi_ulong retcode;
1451};
1452
pbrooka745ec62008-05-06 15:36:17 +00001453struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001454{
bellardf8b0aa22007-11-11 23:03:42 +00001455 abi_ulong pinfo;
1456 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001457 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001458 struct target_ucontext_v1 uc;
1459 abi_ulong retcode;
1460};
1461
1462struct rt_sigframe_v2
1463{
1464 struct target_siginfo info;
1465 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001466 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001467};
1468
1469#define TARGET_CONFIG_CPU_32 1
1470
1471/*
1472 * For ARM syscalls, we encode the syscall number into the instruction.
1473 */
1474#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1475#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1476
1477/*
1478 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1479 * need two 16-bit instructions.
1480 */
1481#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1482#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1483
blueswir1992f48a2007-10-14 16:27:31 +00001484static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001485 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1486 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1487};
1488
1489
bellard43fff232003-07-09 19:31:39 +00001490#define __get_user_error(x,p,e) __get_user(x, p)
1491
Andreas Färber05390242012-02-25 03:37:53 +01001492static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001493{
1494 return 1;
1495}
1496
pbrooka8c33202008-05-07 23:22:46 +00001497static void
bellard43fff232003-07-09 19:31:39 +00001498setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001499 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001500{
pbrooka8c33202008-05-07 23:22:46 +00001501 __put_user(env->regs[0], &sc->arm_r0);
1502 __put_user(env->regs[1], &sc->arm_r1);
1503 __put_user(env->regs[2], &sc->arm_r2);
1504 __put_user(env->regs[3], &sc->arm_r3);
1505 __put_user(env->regs[4], &sc->arm_r4);
1506 __put_user(env->regs[5], &sc->arm_r5);
1507 __put_user(env->regs[6], &sc->arm_r6);
1508 __put_user(env->regs[7], &sc->arm_r7);
1509 __put_user(env->regs[8], &sc->arm_r8);
1510 __put_user(env->regs[9], &sc->arm_r9);
1511 __put_user(env->regs[10], &sc->arm_r10);
1512 __put_user(env->regs[11], &sc->arm_fp);
1513 __put_user(env->regs[12], &sc->arm_ip);
1514 __put_user(env->regs[13], &sc->arm_sp);
1515 __put_user(env->regs[14], &sc->arm_lr);
1516 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001517#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001518 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001519#endif
1520
pbrooka8c33202008-05-07 23:22:46 +00001521 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1522 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1523 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1524 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001525}
1526
bellard579a97f2007-11-11 14:26:47 +00001527static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001528get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001529{
1530 unsigned long sp = regs->regs[13];
1531
bellard43fff232003-07-09 19:31:39 +00001532 /*
1533 * This is the X/Open sanctioned signal stack switching.
1534 */
pbrook624f7972008-05-31 16:11:38 +00001535 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001536 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001537 /*
1538 * ATPCS B01 mandates 8-byte alignment
1539 */
bellard579a97f2007-11-11 14:26:47 +00001540 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001541}
1542
1543static int
Andreas Färber05390242012-02-25 03:37:53 +01001544setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001545 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001546{
pbrook624f7972008-05-31 16:11:38 +00001547 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001548 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001549 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001550 uint32_t cpsr = cpsr_read(env);
1551
1552 cpsr &= ~CPSR_IT;
1553 if (thumb) {
1554 cpsr |= CPSR_T;
1555 } else {
1556 cpsr &= ~CPSR_T;
1557 }
bellard43fff232003-07-09 19:31:39 +00001558
pbrook624f7972008-05-31 16:11:38 +00001559 if (ka->sa_flags & TARGET_SA_RESTORER) {
1560 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001561 } else {
1562 unsigned int idx = thumb;
1563
pbrook624f7972008-05-31 16:11:38 +00001564 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001565 idx += 2;
1566
1567 if (__put_user(retcodes[idx], rc))
1568 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001569
bellardf8b0aa22007-11-11 23:03:42 +00001570 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001571 }
1572
1573 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001574 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001575 env->regs[14] = retcode;
1576 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001577 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001578
1579 return 0;
1580}
1581
Andreas Färber05390242012-02-25 03:37:53 +01001582static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001583{
1584 int i;
1585 struct target_vfp_sigframe *vfpframe;
1586 vfpframe = (struct target_vfp_sigframe *)regspace;
1587 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1588 __put_user(sizeof(*vfpframe), &vfpframe->size);
1589 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001590 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001591 }
1592 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1593 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1594 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1595 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1596 return (abi_ulong*)(vfpframe+1);
1597}
1598
Andreas Färber05390242012-02-25 03:37:53 +01001599static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1600 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001601{
1602 int i;
1603 struct target_iwmmxt_sigframe *iwmmxtframe;
1604 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1605 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1606 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1607 for (i = 0; i < 16; i++) {
1608 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1609 }
1610 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1611 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1612 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1613 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1614 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1615 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1616 return (abi_ulong*)(iwmmxtframe+1);
1617}
1618
pbrooka8c33202008-05-07 23:22:46 +00001619static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001620 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001621{
pbrooka8c33202008-05-07 23:22:46 +00001622 struct target_sigaltstack stack;
1623 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001624 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001625
1626 /* Clear all the bits of the ucontext we don't use. */
1627 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1628
1629 memset(&stack, 0, sizeof(stack));
1630 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1631 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1632 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1633 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1634
1635 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001636 /* Save coprocessor signal frame. */
1637 regspace = uc->tuc_regspace;
1638 if (arm_feature(env, ARM_FEATURE_VFP)) {
1639 regspace = setup_sigframe_v2_vfp(regspace, env);
1640 }
Peter Maydell08e11252010-11-24 15:20:07 +00001641 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1642 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1643 }
1644
Peter Maydell0d871bd2010-11-24 15:20:05 +00001645 /* Write terminating magic word */
1646 __put_user(0, regspace);
1647
pbrooka8c33202008-05-07 23:22:46 +00001648 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1649 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1650 }
1651}
1652
1653/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001654static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001655 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001656{
1657 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001658 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001659 int i;
bellard43fff232003-07-09 19:31:39 +00001660
bellard579a97f2007-11-11 14:26:47 +00001661 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1662 return;
1663
pbrooka8c33202008-05-07 23:22:46 +00001664 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001665
bellard92319442004-06-19 16:58:13 +00001666 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1667 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001668 goto end;
bellard43fff232003-07-09 19:31:39 +00001669 }
1670
pbrooka8c33202008-05-07 23:22:46 +00001671 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1672 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001673
1674end:
1675 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001676}
1677
pbrook624f7972008-05-31 16:11:38 +00001678static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001679 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001680{
1681 struct sigframe_v2 *frame;
1682 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1683
1684 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1685 return;
1686
1687 setup_sigframe_v2(&frame->uc, set, regs);
1688
1689 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1690 frame_addr + offsetof(struct sigframe_v2, retcode));
1691
1692 unlock_user_struct(frame, frame_addr, 1);
1693}
1694
pbrook624f7972008-05-31 16:11:38 +00001695static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001696 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001697{
1698 if (get_osversion() >= 0x020612) {
1699 setup_frame_v2(usig, ka, set, regs);
1700 } else {
1701 setup_frame_v1(usig, ka, set, regs);
1702 }
bellard43fff232003-07-09 19:31:39 +00001703}
1704
bellard579a97f2007-11-11 14:26:47 +00001705/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001706static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001707 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001708 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001709{
pbrooka745ec62008-05-06 15:36:17 +00001710 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001711 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001712 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001713 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001714 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001715
bellard579a97f2007-11-11 14:26:47 +00001716 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001717 return /* 1 */;
1718
pbrooka745ec62008-05-06 15:36:17 +00001719 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001720 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001721 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001722 __put_user(uc_addr, &frame->puc);
1723 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001724
1725 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001726 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001727
thsa04e1342007-09-27 13:57:58 +00001728 memset(&stack, 0, sizeof(stack));
1729 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1730 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1731 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001732 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001733
pbrooka8c33202008-05-07 23:22:46 +00001734 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001735 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001736 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001737 goto end;
bellard92319442004-06-19 16:58:13 +00001738 }
bellard43fff232003-07-09 19:31:39 +00001739
pbrooka8c33202008-05-07 23:22:46 +00001740 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1741 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001742
pbrooka8c33202008-05-07 23:22:46 +00001743 env->regs[1] = info_addr;
1744 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001745
1746end:
1747 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001748}
1749
pbrook624f7972008-05-31 16:11:38 +00001750static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001751 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001752 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001753{
1754 struct rt_sigframe_v2 *frame;
1755 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001756 abi_ulong info_addr, uc_addr;
1757
1758 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1759 return /* 1 */;
1760
1761 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1762 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001763 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001764
pbrooka8c33202008-05-07 23:22:46 +00001765 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001766
pbrooka8c33202008-05-07 23:22:46 +00001767 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1768 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001769
pbrooka8c33202008-05-07 23:22:46 +00001770 env->regs[1] = info_addr;
1771 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001772
bellard579a97f2007-11-11 14:26:47 +00001773 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001774}
1775
pbrook624f7972008-05-31 16:11:38 +00001776static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001777 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001778 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001779{
1780 if (get_osversion() >= 0x020612) {
1781 setup_rt_frame_v2(usig, ka, info, set, env);
1782 } else {
1783 setup_rt_frame_v1(usig, ka, info, set, env);
1784 }
1785}
1786
bellard43fff232003-07-09 19:31:39 +00001787static int
Andreas Färber05390242012-02-25 03:37:53 +01001788restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001789{
1790 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001791 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001792
1793 __get_user_error(env->regs[0], &sc->arm_r0, err);
1794 __get_user_error(env->regs[1], &sc->arm_r1, err);
1795 __get_user_error(env->regs[2], &sc->arm_r2, err);
1796 __get_user_error(env->regs[3], &sc->arm_r3, err);
1797 __get_user_error(env->regs[4], &sc->arm_r4, err);
1798 __get_user_error(env->regs[5], &sc->arm_r5, err);
1799 __get_user_error(env->regs[6], &sc->arm_r6, err);
1800 __get_user_error(env->regs[7], &sc->arm_r7, err);
1801 __get_user_error(env->regs[8], &sc->arm_r8, err);
1802 __get_user_error(env->regs[9], &sc->arm_r9, err);
1803 __get_user_error(env->regs[10], &sc->arm_r10, err);
1804 __get_user_error(env->regs[11], &sc->arm_fp, err);
1805 __get_user_error(env->regs[12], &sc->arm_ip, err);
1806 __get_user_error(env->regs[13], &sc->arm_sp, err);
1807 __get_user_error(env->regs[14], &sc->arm_lr, err);
1808 __get_user_error(env->regs[15], &sc->arm_pc, err);
1809#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001810 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001811 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001812#endif
1813
1814 err |= !valid_user_regs(env);
1815
1816 return err;
1817}
1818
Andreas Färber05390242012-02-25 03:37:53 +01001819static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001820{
bellardf8b0aa22007-11-11 23:03:42 +00001821 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001822 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001823 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001824 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001825 int i;
bellard43fff232003-07-09 19:31:39 +00001826
1827 /*
1828 * Since we stacked the signal on a 64-bit boundary,
1829 * then 'sp' should be word aligned here. If it's
1830 * not, then the user is trying to mess with us.
1831 */
bellardf8b0aa22007-11-11 23:03:42 +00001832 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001833 if (frame_addr & 7) {
1834 goto badframe;
1835 }
1836
bellardf8b0aa22007-11-11 23:03:42 +00001837 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1838 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001839
bellard92319442004-06-19 16:58:13 +00001840 if (__get_user(set.sig[0], &frame->sc.oldmask))
1841 goto badframe;
1842 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1843 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1844 goto badframe;
1845 }
bellard43fff232003-07-09 19:31:39 +00001846
bellard92319442004-06-19 16:58:13 +00001847 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001848 sigprocmask(SIG_SETMASK, &host_set, NULL);
1849
1850 if (restore_sigcontext(env, &frame->sc))
1851 goto badframe;
1852
1853#if 0
1854 /* Send SIGTRAP if we're single-stepping */
1855 if (ptrace_cancel_bpt(current))
1856 send_sig(SIGTRAP, current, 1);
1857#endif
bellardf8b0aa22007-11-11 23:03:42 +00001858 unlock_user_struct(frame, frame_addr, 0);
1859 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001860
1861badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001862 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001863 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001864 return 0;
1865}
1866
Andreas Färber05390242012-02-25 03:37:53 +01001867static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001868{
1869 int i;
1870 abi_ulong magic, sz;
1871 uint32_t fpscr, fpexc;
1872 struct target_vfp_sigframe *vfpframe;
1873 vfpframe = (struct target_vfp_sigframe *)regspace;
1874
1875 __get_user(magic, &vfpframe->magic);
1876 __get_user(sz, &vfpframe->size);
1877 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1878 return 0;
1879 }
1880 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001881 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001882 }
1883 __get_user(fpscr, &vfpframe->ufp.fpscr);
1884 vfp_set_fpscr(env, fpscr);
1885 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1886 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1887 * and the exception flag is cleared
1888 */
1889 fpexc |= (1 << 30);
1890 fpexc &= ~((1 << 31) | (1 << 28));
1891 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1892 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1893 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1894 return (abi_ulong*)(vfpframe + 1);
1895}
1896
Andreas Färber05390242012-02-25 03:37:53 +01001897static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1898 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001899{
1900 int i;
1901 abi_ulong magic, sz;
1902 struct target_iwmmxt_sigframe *iwmmxtframe;
1903 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1904
1905 __get_user(magic, &iwmmxtframe->magic);
1906 __get_user(sz, &iwmmxtframe->size);
1907 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1908 return 0;
1909 }
1910 for (i = 0; i < 16; i++) {
1911 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1912 }
1913 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1914 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1915 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1916 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1917 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1918 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1919 return (abi_ulong*)(iwmmxtframe + 1);
1920}
1921
Andreas Färber05390242012-02-25 03:37:53 +01001922static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001923 struct target_ucontext_v2 *uc)
1924{
1925 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001926 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001927
1928 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1929 sigprocmask(SIG_SETMASK, &host_set, NULL);
1930
1931 if (restore_sigcontext(env, &uc->tuc_mcontext))
1932 return 1;
1933
Peter Maydell5f9099d2010-11-24 15:20:06 +00001934 /* Restore coprocessor signal frame */
1935 regspace = uc->tuc_regspace;
1936 if (arm_feature(env, ARM_FEATURE_VFP)) {
1937 regspace = restore_sigframe_v2_vfp(env, regspace);
1938 if (!regspace) {
1939 return 1;
1940 }
1941 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001942 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1943 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1944 if (!regspace) {
1945 return 1;
1946 }
1947 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001948
pbrooka8c33202008-05-07 23:22:46 +00001949 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1950 return 1;
1951
1952#if 0
1953 /* Send SIGTRAP if we're single-stepping */
1954 if (ptrace_cancel_bpt(current))
1955 send_sig(SIGTRAP, current, 1);
1956#endif
1957
1958 return 0;
1959}
1960
Andreas Färber05390242012-02-25 03:37:53 +01001961static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001962{
1963 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001964 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00001965
1966 /*
1967 * Since we stacked the signal on a 64-bit boundary,
1968 * then 'sp' should be word aligned here. If it's
1969 * not, then the user is trying to mess with us.
1970 */
pbrooka8c33202008-05-07 23:22:46 +00001971 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001972 if (frame_addr & 7) {
1973 goto badframe;
1974 }
1975
pbrooka8c33202008-05-07 23:22:46 +00001976 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1977 goto badframe;
1978
1979 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1980 goto badframe;
1981
1982 unlock_user_struct(frame, frame_addr, 0);
1983 return env->regs[0];
1984
1985badframe:
1986 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001987 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00001988 return 0;
1989}
1990
Andreas Färber05390242012-02-25 03:37:53 +01001991long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001992{
1993 if (get_osversion() >= 0x020612) {
1994 return do_sigreturn_v2(env);
1995 } else {
1996 return do_sigreturn_v1(env);
1997 }
1998}
1999
Andreas Färber05390242012-02-25 03:37:53 +01002000static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002001{
bellardf8b0aa22007-11-11 23:03:42 +00002002 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002003 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002004 sigset_t host_set;
2005
2006 /*
2007 * Since we stacked the signal on a 64-bit boundary,
2008 * then 'sp' should be word aligned here. If it's
2009 * not, then the user is trying to mess with us.
2010 */
bellardf8b0aa22007-11-11 23:03:42 +00002011 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002012 if (frame_addr & 7) {
2013 goto badframe;
2014 }
2015
bellardf8b0aa22007-11-11 23:03:42 +00002016 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2017 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002018
bellardb8076a72005-04-07 22:20:31 +00002019 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00002020 sigprocmask(SIG_SETMASK, &host_set, NULL);
2021
bellardb8076a72005-04-07 22:20:31 +00002022 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002023 goto badframe;
2024
pbrooka745ec62008-05-06 15:36:17 +00002025 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 +00002026 goto badframe;
2027
bellard43fff232003-07-09 19:31:39 +00002028#if 0
2029 /* Send SIGTRAP if we're single-stepping */
2030 if (ptrace_cancel_bpt(current))
2031 send_sig(SIGTRAP, current, 1);
2032#endif
bellardf8b0aa22007-11-11 23:03:42 +00002033 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002034 return env->regs[0];
2035
2036badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002037 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002038 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002039 return 0;
2040}
2041
Andreas Färber05390242012-02-25 03:37:53 +01002042static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002043{
2044 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002045 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002046
2047 /*
2048 * Since we stacked the signal on a 64-bit boundary,
2049 * then 'sp' should be word aligned here. If it's
2050 * not, then the user is trying to mess with us.
2051 */
pbrooka745ec62008-05-06 15:36:17 +00002052 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002053 if (frame_addr & 7) {
2054 goto badframe;
2055 }
2056
pbrooka745ec62008-05-06 15:36:17 +00002057 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2058 goto badframe;
2059
pbrooka8c33202008-05-07 23:22:46 +00002060 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2061 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002062
pbrooka745ec62008-05-06 15:36:17 +00002063 unlock_user_struct(frame, frame_addr, 0);
2064 return env->regs[0];
2065
2066badframe:
2067 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002068 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002069 return 0;
2070}
2071
Andreas Färber05390242012-02-25 03:37:53 +01002072long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002073{
2074 if (get_osversion() >= 0x020612) {
2075 return do_rt_sigreturn_v2(env);
2076 } else {
2077 return do_rt_sigreturn_v1(env);
2078 }
2079}
2080
bellard6d5e2162004-09-30 22:04:13 +00002081#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002082
bellard6d5e2162004-09-30 22:04:13 +00002083#define __SUNOS_MAXWIN 31
2084
2085/* This is what SunOS does, so shall I. */
2086struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002087 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002088
blueswir1992f48a2007-10-14 16:27:31 +00002089 abi_ulong sigc_mask; /* sigmask to restore */
2090 abi_ulong sigc_sp; /* stack pointer */
2091 abi_ulong sigc_pc; /* program counter */
2092 abi_ulong sigc_npc; /* next program counter */
2093 abi_ulong sigc_psr; /* for condition codes etc */
2094 abi_ulong sigc_g1; /* User uses these two registers */
2095 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002096
2097 /* Now comes information regarding the users window set
2098 * at the time of the signal.
2099 */
blueswir1992f48a2007-10-14 16:27:31 +00002100 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002101
2102 /* stack ptrs for each regwin buf */
2103 char *sigc_spbuf[__SUNOS_MAXWIN];
2104
2105 /* Windows to restore after signal */
2106 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002107 abi_ulong locals[8];
2108 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002109 } sigc_wbuf[__SUNOS_MAXWIN];
2110};
2111/* A Sparc stack frame */
2112struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002113 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002114 abi_ulong ins[8];
2115 /* It's simpler to treat fp and callers_pc as elements of ins[]
2116 * since we never need to access them ourselves.
2117 */
bellard6d5e2162004-09-30 22:04:13 +00002118 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002119 abi_ulong xargs[6];
2120 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002121};
2122
2123typedef struct {
2124 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002125 abi_ulong psr;
2126 abi_ulong pc;
2127 abi_ulong npc;
2128 abi_ulong y;
2129 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002130 } si_regs;
2131 int si_mask;
2132} __siginfo_t;
2133
2134typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002135 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002136 unsigned long si_fsr;
2137 unsigned long si_fpqdepth;
2138 struct {
2139 unsigned long *insn_addr;
2140 unsigned long insn;
2141 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002142} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002143
2144
2145struct target_signal_frame {
2146 struct sparc_stackf ss;
2147 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002148 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002149 abi_ulong insns[2] __attribute__ ((aligned (8)));
2150 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2151 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002152 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002153};
2154struct target_rt_signal_frame {
2155 struct sparc_stackf ss;
2156 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002157 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002158 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002159 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002160 unsigned int insns[2];
2161 stack_t stack;
2162 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002163 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002164};
2165
bellarde80cfcf2004-12-19 23:18:01 +00002166#define UREG_O0 16
2167#define UREG_O6 22
2168#define UREG_I0 0
2169#define UREG_I1 1
2170#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002171#define UREG_I3 3
2172#define UREG_I4 4
2173#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002174#define UREG_I6 6
2175#define UREG_I7 7
2176#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002177#define UREG_FP UREG_I6
2178#define UREG_SP UREG_O6
2179
pbrook624f7972008-05-31 16:11:38 +00002180static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002181 CPUSPARCState *env,
2182 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002183{
bellard459a4012007-11-11 19:45:10 +00002184 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002185
2186 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002187
2188 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002189 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002190 if (!on_sig_stack(sp)
2191 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2192 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002193 }
bellard459a4012007-11-11 19:45:10 +00002194 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002195}
2196
2197static int
Andreas Färber05390242012-02-25 03:37:53 +01002198setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002199{
2200 int err = 0, i;
2201
bellard6d5e2162004-09-30 22:04:13 +00002202 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00002203 err |= __put_user(env->pc, &si->si_regs.pc);
2204 err |= __put_user(env->npc, &si->si_regs.npc);
2205 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002206 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00002207 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
2208 }
bellarda315a142005-01-30 22:59:18 +00002209 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002210 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002211 }
bellard6d5e2162004-09-30 22:04:13 +00002212 err |= __put_user(mask, &si->si_mask);
2213 return err;
2214}
bellarde80cfcf2004-12-19 23:18:01 +00002215
bellard80a9d032005-01-03 23:31:27 +00002216#if 0
bellard6d5e2162004-09-30 22:04:13 +00002217static int
2218setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002219 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002220{
2221 int err = 0;
2222
2223 err |= __put_user(mask, &sc->sigc_mask);
2224 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2225 err |= __put_user(env->pc, &sc->sigc_pc);
2226 err |= __put_user(env->npc, &sc->sigc_npc);
2227 err |= __put_user(env->psr, &sc->sigc_psr);
2228 err |= __put_user(env->gregs[1], &sc->sigc_g1);
2229 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
2230
2231 return err;
2232}
bellard80a9d032005-01-03 23:31:27 +00002233#endif
bellard6d5e2162004-09-30 22:04:13 +00002234#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2235
pbrook624f7972008-05-31 16:11:38 +00002236static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002237 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002238{
bellard459a4012007-11-11 19:45:10 +00002239 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002240 struct target_signal_frame *sf;
2241 int sigframe_size, err, i;
2242
2243 /* 1. Make sure everything is clean */
2244 //synchronize_user_stack();
2245
2246 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002247 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002248
bellard459a4012007-11-11 19:45:10 +00002249 sf = lock_user(VERIFY_WRITE, sf_addr,
2250 sizeof(struct target_signal_frame), 0);
2251 if (!sf)
2252 goto sigsegv;
2253
bellarde80cfcf2004-12-19 23:18:01 +00002254 //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 +00002255#if 0
2256 if (invalid_frame_pointer(sf, sigframe_size))
2257 goto sigill_and_return;
2258#endif
2259 /* 2. Save the current process state */
2260 err = setup___siginfo(&sf->info, env, set->sig[0]);
2261 err |= __put_user(0, &sf->extra_size);
2262
2263 //err |= save_fpu_state(regs, &sf->fpu_state);
2264 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
2265
2266 err |= __put_user(set->sig[0], &sf->info.si_mask);
2267 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2268 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
2269 }
2270
bellarda315a142005-01-30 22:59:18 +00002271 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002272 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002273 }
bellarda315a142005-01-30 22:59:18 +00002274 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002275 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002276 }
bellard6d5e2162004-09-30 22:04:13 +00002277 if (err)
2278 goto sigsegv;
2279
2280 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002281 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002282 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002283 env->regwptr[UREG_I1] = sf_addr +
2284 offsetof(struct target_signal_frame, info);
2285 env->regwptr[UREG_I2] = sf_addr +
2286 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002287
2288 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002289 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002290 env->npc = (env->pc + 4);
2291 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002292 if (ka->sa_restorer)
2293 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002294 else {
bellard775b58d2007-11-11 16:22:17 +00002295 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002296
2297 env->regwptr[UREG_I7] = sf_addr +
2298 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002299
2300 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002301 val32 = 0x821020d8;
2302 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002303
2304 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002305 val32 = 0x91d02010;
2306 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002307 if (err)
2308 goto sigsegv;
2309
2310 /* Flush instruction space. */
2311 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002312 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002313 }
bellard459a4012007-11-11 19:45:10 +00002314 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002315 return;
bellard459a4012007-11-11 19:45:10 +00002316#if 0
2317sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002318 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002319#endif
bellard6d5e2162004-09-30 22:04:13 +00002320sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002321 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002322 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002323 force_sig(TARGET_SIGSEGV);
2324}
2325static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002326restore_fpu_state(CPUSPARCState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00002327{
2328 int err;
2329#if 0
2330#ifdef CONFIG_SMP
2331 if (current->flags & PF_USEDFPU)
2332 regs->psr &= ~PSR_EF;
2333#else
2334 if (current == last_task_used_math) {
2335 last_task_used_math = 0;
2336 regs->psr &= ~PSR_EF;
2337 }
2338#endif
2339 current->used_math = 1;
2340 current->flags &= ~PF_USEDFPU;
2341#endif
2342#if 0
2343 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
2344 return -EFAULT;
2345#endif
2346
bellardfafffae2006-10-28 12:09:16 +00002347 /* XXX: incorrect */
Blue Swirl8954bae2012-07-30 15:29:11 +00002348 err = copy_from_user(&env->fpr[0], fpu->si_float_regs[0],
2349 (sizeof(abi_ulong) * 32));
bellard6d5e2162004-09-30 22:04:13 +00002350 err |= __get_user(env->fsr, &fpu->si_fsr);
2351#if 0
2352 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
2353 if (current->thread.fpqdepth != 0)
2354 err |= __copy_from_user(&current->thread.fpqueue[0],
2355 &fpu->si_fpqueue[0],
2356 ((sizeof(unsigned long) +
2357 (sizeof(unsigned long *)))*16));
2358#endif
2359 return err;
2360}
2361
2362
pbrook624f7972008-05-31 16:11:38 +00002363static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002364 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002365 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002366{
2367 fprintf(stderr, "setup_rt_frame: not implemented\n");
2368}
2369
Andreas Färber05390242012-02-25 03:37:53 +01002370long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002371{
bellardf8b0aa22007-11-11 23:03:42 +00002372 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002373 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002374 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002375 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002376 sigset_t host_set;
bellarde80cfcf2004-12-19 23:18:01 +00002377 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00002378
bellardf8b0aa22007-11-11 23:03:42 +00002379 sf_addr = env->regwptr[UREG_FP];
2380 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2381 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002382#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002383 fprintf(stderr, "sigreturn\n");
2384 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 +00002385#endif
bellarde80cfcf2004-12-19 23:18:01 +00002386 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002387
2388 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002389
bellardf8b0aa22007-11-11 23:03:42 +00002390 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002391 goto segv_and_exit;
2392
2393 err = __get_user(pc, &sf->info.si_regs.pc);
2394 err |= __get_user(npc, &sf->info.si_regs.npc);
2395
bellard6d5e2162004-09-30 22:04:13 +00002396 if ((pc | npc) & 3)
2397 goto segv_and_exit;
2398
2399 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00002400 err |= __get_user(up_psr, &sf->info.si_regs.psr);
2401
bellard6d5e2162004-09-30 22:04:13 +00002402 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002403 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2404 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2405
2406 env->pc = pc;
2407 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00002408 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002409 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002410 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2411 }
bellarda315a142005-01-30 22:59:18 +00002412 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002413 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2414 }
bellard6d5e2162004-09-30 22:04:13 +00002415
Peter Maydell2aec3a22011-06-16 17:37:14 +01002416 /* FIXME: implement FPU save/restore:
2417 * __get_user(fpu_save, &sf->fpu_save);
2418 * if (fpu_save)
2419 * err |= restore_fpu_state(env, fpu_save);
2420 */
bellard6d5e2162004-09-30 22:04:13 +00002421
2422 /* This is pretty much atomic, no amount locking would prevent
2423 * the races which exist anyways.
2424 */
2425 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002426 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2427 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
2428 }
2429
2430 target_to_host_sigset_internal(&host_set, &set);
2431 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002432
2433 if (err)
2434 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002435 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002436 return env->regwptr[0];
2437
2438segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002439 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002440 force_sig(TARGET_SIGSEGV);
2441}
2442
Andreas Färber05390242012-02-25 03:37:53 +01002443long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002444{
2445 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002446 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002447}
2448
bellard459a4012007-11-11 19:45:10 +00002449#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002450#define MC_TSTATE 0
2451#define MC_PC 1
2452#define MC_NPC 2
2453#define MC_Y 3
2454#define MC_G1 4
2455#define MC_G2 5
2456#define MC_G3 6
2457#define MC_G4 7
2458#define MC_G5 8
2459#define MC_G6 9
2460#define MC_G7 10
2461#define MC_O0 11
2462#define MC_O1 12
2463#define MC_O2 13
2464#define MC_O3 14
2465#define MC_O4 15
2466#define MC_O5 16
2467#define MC_O6 17
2468#define MC_O7 18
2469#define MC_NGREG 19
2470
Anthony Liguoric227f092009-10-01 16:12:16 -05002471typedef abi_ulong target_mc_greg_t;
2472typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002473
2474struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002475 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002476 uint32_t mcfq_insn;
2477};
2478
2479struct target_mc_fpu {
2480 union {
2481 uint32_t sregs[32];
2482 uint64_t dregs[32];
2483 //uint128_t qregs[16];
2484 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002485 abi_ulong mcfpu_fsr;
2486 abi_ulong mcfpu_fprs;
2487 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002488 struct target_mc_fq *mcfpu_fq;
2489 unsigned char mcfpu_qcnt;
2490 unsigned char mcfpu_qentsz;
2491 unsigned char mcfpu_enab;
2492};
Anthony Liguoric227f092009-10-01 16:12:16 -05002493typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002494
2495typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002496 target_mc_gregset_t mc_gregs;
2497 target_mc_greg_t mc_fp;
2498 target_mc_greg_t mc_i7;
2499 target_mc_fpu_t mc_fpregs;
2500} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002501
2502struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002503 struct target_ucontext *tuc_link;
2504 abi_ulong tuc_flags;
2505 target_sigset_t tuc_sigmask;
2506 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002507};
2508
2509/* A V9 register window */
2510struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002511 abi_ulong locals[8];
2512 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002513};
2514
2515#define TARGET_STACK_BIAS 2047
2516
2517/* {set, get}context() needed for 64-bit SparcLinux userland. */
2518void sparc64_set_context(CPUSPARCState *env)
2519{
bellard459a4012007-11-11 19:45:10 +00002520 abi_ulong ucp_addr;
2521 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002522 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002523 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002524 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002525 int err;
2526 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002527
bellard459a4012007-11-11 19:45:10 +00002528 ucp_addr = env->regwptr[UREG_I0];
2529 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2530 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002531 grp = &ucp->tuc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002532 err = __get_user(pc, &((*grp)[MC_PC]));
2533 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002534 if (err || ((pc | npc) & 3))
2535 goto do_sigsegv;
2536 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002537 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002538 sigset_t set;
2539
2540 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002541 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002542 goto do_sigsegv;
2543 } else {
bellard459a4012007-11-11 19:45:10 +00002544 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002545 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002546 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002547 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002548 err |= __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002549 }
blueswir15bfb56b2007-10-05 17:01:51 +00002550 if (err)
2551 goto do_sigsegv;
2552 }
2553 target_to_host_sigset_internal(&set, &target_set);
2554 sigprocmask(SIG_SETMASK, &set, NULL);
2555 }
2556 env->pc = pc;
2557 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002558 err |= __get_user(env->y, &((*grp)[MC_Y]));
2559 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002560 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002561 cpu_put_ccr(env, tstate >> 32);
2562 cpu_put_cwp64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002563 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2564 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2565 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2566 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2567 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2568 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2569 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2570 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2571 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2572 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2573 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2574 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2575 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2576 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2577 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002578
Aurelien Jarno60e99242010-03-29 02:12:51 +02002579 err |= __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2580 err |= __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002581
bellard459a4012007-11-11 19:45:10 +00002582 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2583 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2584 abi_ulong) != 0)
2585 goto do_sigsegv;
2586 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2587 abi_ulong) != 0)
2588 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002589 /* FIXME this does not match how the kernel handles the FPU in
2590 * its sparc64_set_context implementation. In particular the FPU
2591 * is only restored if fenab is non-zero in:
2592 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2593 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002594 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002595 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002596 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2597 for (i = 0; i < 64; i++, src++) {
2598 if (i & 1) {
2599 err |= __get_user(env->fpr[i/2].l.lower, src);
2600 } else {
2601 err |= __get_user(env->fpr[i/2].l.upper, src);
2602 }
2603 }
bellard459a4012007-11-11 19:45:10 +00002604 }
bellard579a97f2007-11-11 14:26:47 +00002605 err |= __get_user(env->fsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002606 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
bellard579a97f2007-11-11 14:26:47 +00002607 err |= __get_user(env->gsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002608 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002609 if (err)
2610 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002611 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002612 return;
2613 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002614 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002615 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002616}
2617
2618void sparc64_get_context(CPUSPARCState *env)
2619{
bellard459a4012007-11-11 19:45:10 +00002620 abi_ulong ucp_addr;
2621 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002622 target_mc_gregset_t *grp;
2623 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002624 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002625 int err;
2626 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002627 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002628 sigset_t set;
2629
bellard459a4012007-11-11 19:45:10 +00002630 ucp_addr = env->regwptr[UREG_I0];
2631 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2632 goto do_sigsegv;
2633
Aurelien Jarno60e99242010-03-29 02:12:51 +02002634 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002635 grp = &mcp->mc_gregs;
2636
2637 /* Skip over the trap instruction, first. */
2638 env->pc = env->npc;
2639 env->npc += 4;
2640
2641 err = 0;
2642
2643 sigprocmask(0, NULL, &set);
2644 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002645 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002646 err |= __put_user(target_set.sig[0],
Aurelien Jarno60e99242010-03-29 02:12:51 +02002647 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002648 } else {
2649 abi_ulong *src, *dst;
2650 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002651 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002652 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002653 err |= __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002654 }
blueswir15bfb56b2007-10-05 17:01:51 +00002655 if (err)
2656 goto do_sigsegv;
2657 }
2658
bellard459a4012007-11-11 19:45:10 +00002659 /* XXX: tstate must be saved properly */
2660 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002661 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2662 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2663 err |= __put_user(env->y, &((*grp)[MC_Y]));
2664 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2665 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2666 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2667 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2668 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2669 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2670 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2671 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2672 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2673 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2674 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2675 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2676 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2677 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2678 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002679
bellard459a4012007-11-11 19:45:10 +00002680 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2681 fp = i7 = 0;
2682 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2683 abi_ulong) != 0)
2684 goto do_sigsegv;
2685 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2686 abi_ulong) != 0)
2687 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002688 err |= __put_user(fp, &(mcp->mc_fp));
2689 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002690
bellard459a4012007-11-11 19:45:10 +00002691 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002692 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2693 for (i = 0; i < 64; i++, dst++) {
2694 if (i & 1) {
2695 err |= __put_user(env->fpr[i/2].l.lower, dst);
2696 } else {
2697 err |= __put_user(env->fpr[i/2].l.upper, dst);
2698 }
2699 }
bellard459a4012007-11-11 19:45:10 +00002700 }
bellard579a97f2007-11-11 14:26:47 +00002701 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2702 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2703 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002704
2705 if (err)
2706 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002707 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002708 return;
2709 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002710 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002711 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002712}
2713#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002714#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002715
Richard Hendersonff970902013-02-10 10:30:42 -08002716# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002717struct target_sigcontext {
2718 uint32_t sc_regmask; /* Unused */
2719 uint32_t sc_status;
2720 uint64_t sc_pc;
2721 uint64_t sc_regs[32];
2722 uint64_t sc_fpregs[32];
2723 uint32_t sc_ownedfp; /* Unused */
2724 uint32_t sc_fpc_csr;
2725 uint32_t sc_fpc_eir; /* Unused */
2726 uint32_t sc_used_math;
2727 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002728 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002729 uint64_t sc_mdhi;
2730 uint64_t sc_mdlo;
2731 target_ulong sc_hi1; /* Was sc_cause */
2732 target_ulong sc_lo1; /* Was sc_badvaddr */
2733 target_ulong sc_hi2; /* Was sc_sigset[4] */
2734 target_ulong sc_lo2;
2735 target_ulong sc_hi3;
2736 target_ulong sc_lo3;
2737};
Richard Hendersonff970902013-02-10 10:30:42 -08002738# else /* N32 || N64 */
2739struct target_sigcontext {
2740 uint64_t sc_regs[32];
2741 uint64_t sc_fpregs[32];
2742 uint64_t sc_mdhi;
2743 uint64_t sc_hi1;
2744 uint64_t sc_hi2;
2745 uint64_t sc_hi3;
2746 uint64_t sc_mdlo;
2747 uint64_t sc_lo1;
2748 uint64_t sc_lo2;
2749 uint64_t sc_lo3;
2750 uint64_t sc_pc;
2751 uint32_t sc_fpc_csr;
2752 uint32_t sc_used_math;
2753 uint32_t sc_dsp;
2754 uint32_t sc_reserved;
2755};
2756# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002757
2758struct sigframe {
2759 uint32_t sf_ass[4]; /* argument save space for o32 */
2760 uint32_t sf_code[2]; /* signal trampoline */
2761 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002762 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002763};
2764
pbrook0b1bcb02009-04-21 01:41:10 +00002765struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002766 target_ulong tuc_flags;
2767 target_ulong tuc_link;
2768 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002769 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002770 struct target_sigcontext tuc_mcontext;
2771 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002772};
2773
2774struct target_rt_sigframe {
2775 uint32_t rs_ass[4]; /* argument save space for o32 */
2776 uint32_t rs_code[2]; /* signal trampoline */
2777 struct target_siginfo rs_info;
2778 struct target_ucontext rs_uc;
2779};
2780
bellard106ec872006-06-27 21:08:10 +00002781/* Install trampoline to jump back from signal handler */
2782static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2783{
Richard Henderson084d0492013-02-10 10:30:44 -08002784 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002785
2786 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002787 * Set up the return code ...
2788 *
2789 * li v0, __NR__foo_sigreturn
2790 * syscall
2791 */
bellard106ec872006-06-27 21:08:10 +00002792
Richard Henderson084d0492013-02-10 10:30:44 -08002793 err |= __put_user(0x24020000 + syscall, tramp + 0);
bellard106ec872006-06-27 21:08:10 +00002794 err |= __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002795 return err;
2796}
2797
2798static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002799setup_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002800{
2801 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002802 int i;
bellard106ec872006-06-27 21:08:10 +00002803
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002804 err |= __put_user(exception_resume_pc(regs), &sc->sc_pc);
2805 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002806
Richard Henderson084d0492013-02-10 10:30:44 -08002807 __put_user(0, &sc->sc_regs[0]);
2808 for (i = 1; i < 32; ++i) {
2809 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
2810 }
bellard106ec872006-06-27 21:08:10 +00002811
thsb5dc7732008-06-27 10:02:35 +00002812 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2813 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002814
Richard Henderson084d0492013-02-10 10:30:44 -08002815 /* Rather than checking for dsp existence, always copy. The storage
2816 would just be garbage otherwise. */
2817 err |= __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2818 err |= __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2819 err |= __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2820 err |= __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2821 err |= __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2822 err |= __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
2823 {
2824 uint32_t dsp = cpu_rddsp(0x3ff, regs);
2825 err |= __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002826 }
Richard Henderson084d0492013-02-10 10:30:44 -08002827
2828 err |= __put_user(1, &sc->sc_used_math);
2829
2830 for (i = 0; i < 32; ++i) {
2831 err |= __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002832 }
bellard106ec872006-06-27 21:08:10 +00002833
bellard106ec872006-06-27 21:08:10 +00002834 return err;
2835}
2836
2837static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002838restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002839{
2840 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002841 int i;
bellard106ec872006-06-27 21:08:10 +00002842
2843 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2844
thsb5dc7732008-06-27 10:02:35 +00002845 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2846 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002847
Richard Henderson084d0492013-02-10 10:30:44 -08002848 for (i = 1; i < 32; ++i) {
2849 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002850 }
2851
Richard Henderson084d0492013-02-10 10:30:44 -08002852 err |= __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2853 err |= __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2854 err |= __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2855 err |= __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2856 err |= __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2857 err |= __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
2858 {
2859 uint32_t dsp;
2860 err |= __get_user(dsp, &sc->sc_dsp);
2861 cpu_wrdsp(dsp, 0x3ff, regs);
2862 }
2863
2864 for (i = 0; i < 32; ++i) {
2865 err |= __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
2866 }
2867
bellard106ec872006-06-27 21:08:10 +00002868 return err;
2869}
Richard Hendersonff970902013-02-10 10:30:42 -08002870
bellard106ec872006-06-27 21:08:10 +00002871/*
2872 * Determine which stack to use..
2873 */
bellard579a97f2007-11-11 14:26:47 +00002874static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002875get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002876{
2877 unsigned long sp;
2878
2879 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002880 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002881
2882 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002883 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002884 * above the user stack, 16-bytes before the next lowest
2885 * 16 byte boundary. Try to avoid trashing it.
2886 */
2887 sp -= 32;
2888
bellard106ec872006-06-27 21:08:10 +00002889 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002890 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002891 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2892 }
bellard106ec872006-06-27 21:08:10 +00002893
bellard579a97f2007-11-11 14:26:47 +00002894 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002895}
2896
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002897static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2898{
2899 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2900 env->hflags &= ~MIPS_HFLAG_M16;
2901 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2902 env->active_tc.PC &= ~(target_ulong) 1;
2903 }
2904}
2905
Richard Hendersonff970902013-02-10 10:30:42 -08002906# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002907/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002908static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002909 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002910{
2911 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002912 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002913 int i;
2914
bellard579a97f2007-11-11 14:26:47 +00002915 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2916 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002917 goto give_sigsegv;
2918
2919 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2920
2921 if(setup_sigcontext(regs, &frame->sf_sc))
2922 goto give_sigsegv;
2923
2924 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2925 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2926 goto give_sigsegv;
2927 }
2928
2929 /*
2930 * Arguments to signal handler:
2931 *
2932 * a0 = signal number
2933 * a1 = 0 (should be cause)
2934 * a2 = pointer to struct sigcontext
2935 *
2936 * $25 and PC point to the signal handler, $29 points to the
2937 * struct sigframe.
2938 */
thsb5dc7732008-06-27 10:02:35 +00002939 regs->active_tc.gpr[ 4] = sig;
2940 regs->active_tc.gpr[ 5] = 0;
2941 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2942 regs->active_tc.gpr[29] = frame_addr;
2943 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002944 /* The original kernel code sets CP0_EPC to the handler
2945 * since it returns to userland using eret
2946 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002947 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002948 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002949 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002950 return;
2951
2952give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002953 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002954 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002955}
2956
Andreas Färber05390242012-02-25 03:37:53 +01002957long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002958{
ths388bb212007-05-13 13:58:00 +00002959 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002960 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002961 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002962 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002963 int i;
bellard106ec872006-06-27 21:08:10 +00002964
2965#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002966 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002967#endif
thsb5dc7732008-06-27 10:02:35 +00002968 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002969 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002970 goto badframe;
2971
ths388bb212007-05-13 13:58:00 +00002972 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002973 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2974 goto badframe;
ths388bb212007-05-13 13:58:00 +00002975 }
bellard106ec872006-06-27 21:08:10 +00002976
ths388bb212007-05-13 13:58:00 +00002977 target_to_host_sigset_internal(&blocked, &target_set);
2978 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002979
ths388bb212007-05-13 13:58:00 +00002980 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002981 goto badframe;
2982
2983#if 0
ths388bb212007-05-13 13:58:00 +00002984 /*
2985 * Don't let your children do this ...
2986 */
2987 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002988 "move\t$29, %0\n\t"
2989 "j\tsyscall_exit"
2990 :/* no outputs */
2991 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002992 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002993#endif
ths3b46e622007-09-17 08:09:54 +00002994
thsb5dc7732008-06-27 10:02:35 +00002995 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002996 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00002997 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002998 * maybe a problem with nested signals ? */
2999 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003000 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003001
3002badframe:
ths388bb212007-05-13 13:58:00 +00003003 force_sig(TARGET_SIGSEGV/*, current*/);
3004 return 0;
bellard106ec872006-06-27 21:08:10 +00003005}
Richard Hendersonff970902013-02-10 10:30:42 -08003006# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003007
pbrook624f7972008-05-31 16:11:38 +00003008static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003009 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003010 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003011{
pbrook0b1bcb02009-04-21 01:41:10 +00003012 struct target_rt_sigframe *frame;
3013 abi_ulong frame_addr;
3014 int i;
3015
3016 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3017 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3018 goto give_sigsegv;
3019
3020 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3021
3022 copy_siginfo_to_user(&frame->rs_info, info);
3023
Aurelien Jarno60e99242010-03-29 02:12:51 +02003024 __put_user(0, &frame->rs_uc.tuc_flags);
3025 __put_user(0, &frame->rs_uc.tuc_link);
3026 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3027 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003028 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003029 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003030
Aurelien Jarno60e99242010-03-29 02:12:51 +02003031 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003032
3033 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003034 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003035 }
3036
3037 /*
3038 * Arguments to signal handler:
3039 *
3040 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003041 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003042 * a2 = pointer to struct ucontext
3043 *
3044 * $25 and PC point to the signal handler, $29 points to the
3045 * struct sigframe.
3046 */
3047 env->active_tc.gpr[ 4] = sig;
3048 env->active_tc.gpr[ 5] = frame_addr
3049 + offsetof(struct target_rt_sigframe, rs_info);
3050 env->active_tc.gpr[ 6] = frame_addr
3051 + offsetof(struct target_rt_sigframe, rs_uc);
3052 env->active_tc.gpr[29] = frame_addr;
3053 env->active_tc.gpr[31] = frame_addr
3054 + offsetof(struct target_rt_sigframe, rs_code);
3055 /* The original kernel code sets CP0_EPC to the handler
3056 * since it returns to userland using eret
3057 * we cannot do this here, and we must set PC directly */
3058 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003059 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003060 unlock_user_struct(frame, frame_addr, 1);
3061 return;
3062
3063give_sigsegv:
3064 unlock_user_struct(frame, frame_addr, 1);
3065 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003066}
3067
Andreas Färber05390242012-02-25 03:37:53 +01003068long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003069{
pbrook0b1bcb02009-04-21 01:41:10 +00003070 struct target_rt_sigframe *frame;
3071 abi_ulong frame_addr;
3072 sigset_t blocked;
3073
3074#if defined(DEBUG_SIGNAL)
3075 fprintf(stderr, "do_rt_sigreturn\n");
3076#endif
3077 frame_addr = env->active_tc.gpr[29];
3078 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3079 goto badframe;
3080
Aurelien Jarno60e99242010-03-29 02:12:51 +02003081 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
pbrook0b1bcb02009-04-21 01:41:10 +00003082 sigprocmask(SIG_SETMASK, &blocked, NULL);
3083
Aurelien Jarno60e99242010-03-29 02:12:51 +02003084 if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
pbrook0b1bcb02009-04-21 01:41:10 +00003085 goto badframe;
3086
3087 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003088 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003089 0, get_sp_from_cpustate(env)) == -EFAULT)
3090 goto badframe;
3091
3092 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003093 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003094 /* I am not sure this is right, but it seems to work
3095 * maybe a problem with nested signals ? */
3096 env->CP0_EPC = 0;
3097 return -TARGET_QEMU_ESIGRETURN;
3098
3099badframe:
3100 force_sig(TARGET_SIGSEGV/*, current*/);
3101 return 0;
bellard106ec872006-06-27 21:08:10 +00003102}
bellard6d5e2162004-09-30 22:04:13 +00003103
thsc3b5bc82007-12-02 06:31:25 +00003104#elif defined(TARGET_SH4)
3105
3106/*
3107 * code and data structures from linux kernel:
3108 * include/asm-sh/sigcontext.h
3109 * arch/sh/kernel/signal.c
3110 */
3111
3112struct target_sigcontext {
3113 target_ulong oldmask;
3114
3115 /* CPU registers */
3116 target_ulong sc_gregs[16];
3117 target_ulong sc_pc;
3118 target_ulong sc_pr;
3119 target_ulong sc_sr;
3120 target_ulong sc_gbr;
3121 target_ulong sc_mach;
3122 target_ulong sc_macl;
3123
3124 /* FPU registers */
3125 target_ulong sc_fpregs[16];
3126 target_ulong sc_xfpregs[16];
3127 unsigned int sc_fpscr;
3128 unsigned int sc_fpul;
3129 unsigned int sc_ownedfp;
3130};
3131
3132struct target_sigframe
3133{
3134 struct target_sigcontext sc;
3135 target_ulong extramask[TARGET_NSIG_WORDS-1];
3136 uint16_t retcode[3];
3137};
3138
3139
3140struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003141 target_ulong tuc_flags;
3142 struct target_ucontext *tuc_link;
3143 target_stack_t tuc_stack;
3144 struct target_sigcontext tuc_mcontext;
3145 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003146};
3147
3148struct target_rt_sigframe
3149{
3150 struct target_siginfo info;
3151 struct target_ucontext uc;
3152 uint16_t retcode[3];
3153};
3154
3155
3156#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3157#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3158
pbrook624f7972008-05-31 16:11:38 +00003159static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003160 unsigned long sp, size_t frame_size)
3161{
pbrook624f7972008-05-31 16:11:38 +00003162 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003163 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3164 }
3165
3166 return (sp - frame_size) & -8ul;
3167}
3168
3169static int setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003170 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003171{
3172 int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003173 int i;
thsc3b5bc82007-12-02 06:31:25 +00003174
3175#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
3176 COPY(gregs[0]); COPY(gregs[1]);
3177 COPY(gregs[2]); COPY(gregs[3]);
3178 COPY(gregs[4]); COPY(gregs[5]);
3179 COPY(gregs[6]); COPY(gregs[7]);
3180 COPY(gregs[8]); COPY(gregs[9]);
3181 COPY(gregs[10]); COPY(gregs[11]);
3182 COPY(gregs[12]); COPY(gregs[13]);
3183 COPY(gregs[14]); COPY(gregs[15]);
3184 COPY(gbr); COPY(mach);
3185 COPY(macl); COPY(pr);
3186 COPY(sr); COPY(pc);
3187#undef COPY
3188
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003189 for (i=0; i<16; i++) {
3190 err |= __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
3191 }
3192 err |= __put_user(regs->fpscr, &sc->sc_fpscr);
3193 err |= __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003194
3195 /* non-iBCS2 extensions.. */
3196 err |= __put_user(mask, &sc->oldmask);
3197
3198 return err;
3199}
3200
Andreas Färber05390242012-02-25 03:37:53 +01003201static int restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003202 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003203{
3204 unsigned int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003205 int i;
thsc3b5bc82007-12-02 06:31:25 +00003206
3207#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
3208 COPY(gregs[1]);
3209 COPY(gregs[2]); COPY(gregs[3]);
3210 COPY(gregs[4]); COPY(gregs[5]);
3211 COPY(gregs[6]); COPY(gregs[7]);
3212 COPY(gregs[8]); COPY(gregs[9]);
3213 COPY(gregs[10]); COPY(gregs[11]);
3214 COPY(gregs[12]); COPY(gregs[13]);
3215 COPY(gregs[14]); COPY(gregs[15]);
3216 COPY(gbr); COPY(mach);
3217 COPY(macl); COPY(pr);
3218 COPY(sr); COPY(pc);
3219#undef COPY
3220
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003221 for (i=0; i<16; i++) {
3222 err |= __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
3223 }
3224 err |= __get_user(regs->fpscr, &sc->sc_fpscr);
3225 err |= __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003226
3227 regs->tra = -1; /* disable syscall checks */
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003228 err |= __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003229 return err;
3230}
3231
pbrook624f7972008-05-31 16:11:38 +00003232static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003233 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003234{
3235 struct target_sigframe *frame;
3236 abi_ulong frame_addr;
3237 int i;
3238 int err = 0;
3239 int signal;
3240
3241 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3242 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3243 goto give_sigsegv;
3244
3245 signal = current_exec_domain_sig(sig);
3246
3247 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
3248
3249 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
3250 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
3251 }
3252
3253 /* Set up to return from userspace. If provided, use a stub
3254 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003255 if (ka->sa_flags & TARGET_SA_RESTORER) {
3256 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003257 } else {
3258 /* Generate return code (system call to sigreturn) */
3259 err |= __put_user(MOVW(2), &frame->retcode[0]);
3260 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3261 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
3262 regs->pr = (unsigned long) frame->retcode;
3263 }
3264
3265 if (err)
3266 goto give_sigsegv;
3267
3268 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003269 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003270 regs->gregs[4] = signal; /* Arg for signal handler */
3271 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003272 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003273 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003274
3275 unlock_user_struct(frame, frame_addr, 1);
3276 return;
3277
3278give_sigsegv:
3279 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003280 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003281}
3282
pbrook624f7972008-05-31 16:11:38 +00003283static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003284 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003285 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003286{
3287 struct target_rt_sigframe *frame;
3288 abi_ulong frame_addr;
3289 int i;
3290 int err = 0;
3291 int signal;
3292
3293 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3294 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3295 goto give_sigsegv;
3296
3297 signal = current_exec_domain_sig(sig);
3298
3299 err |= copy_siginfo_to_user(&frame->info, info);
3300
3301 /* Create the ucontext. */
Aurelien Jarno60e99242010-03-29 02:12:51 +02003302 err |= __put_user(0, &frame->uc.tuc_flags);
3303 err |= __put_user(0, (unsigned long *)&frame->uc.tuc_link);
balrog526ccb72008-07-16 12:13:52 +00003304 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003305 &frame->uc.tuc_stack.ss_sp);
thsc3b5bc82007-12-02 06:31:25 +00003306 err |= __put_user(sas_ss_flags(regs->gregs[15]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003307 &frame->uc.tuc_stack.ss_flags);
thsc3b5bc82007-12-02 06:31:25 +00003308 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003309 &frame->uc.tuc_stack.ss_size);
3310 err |= setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003311 regs, set->sig[0]);
3312 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003313 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003314 }
3315
3316 /* Set up to return from userspace. If provided, use a stub
3317 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003318 if (ka->sa_flags & TARGET_SA_RESTORER) {
3319 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003320 } else {
3321 /* Generate return code (system call to sigreturn) */
3322 err |= __put_user(MOVW(2), &frame->retcode[0]);
3323 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3324 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
3325 regs->pr = (unsigned long) frame->retcode;
3326 }
3327
3328 if (err)
3329 goto give_sigsegv;
3330
3331 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003332 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003333 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003334 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3335 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003336 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003337
3338 unlock_user_struct(frame, frame_addr, 1);
3339 return;
3340
3341give_sigsegv:
3342 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003343 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003344}
3345
Andreas Färber05390242012-02-25 03:37:53 +01003346long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003347{
3348 struct target_sigframe *frame;
3349 abi_ulong frame_addr;
3350 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003351 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003352 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003353 int i;
3354 int err = 0;
3355
3356#if defined(DEBUG_SIGNAL)
3357 fprintf(stderr, "do_sigreturn\n");
3358#endif
3359 frame_addr = regs->gregs[15];
3360 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3361 goto badframe;
3362
3363 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
3364 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3365 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
3366 }
3367
3368 if (err)
3369 goto badframe;
3370
3371 target_to_host_sigset_internal(&blocked, &target_set);
3372 sigprocmask(SIG_SETMASK, &blocked, NULL);
3373
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003374 if (restore_sigcontext(regs, &frame->sc, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003375 goto badframe;
3376
3377 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003378 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003379
3380badframe:
3381 unlock_user_struct(frame, frame_addr, 0);
3382 force_sig(TARGET_SIGSEGV);
3383 return 0;
3384}
3385
Andreas Färber05390242012-02-25 03:37:53 +01003386long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003387{
3388 struct target_rt_sigframe *frame;
3389 abi_ulong frame_addr;
3390 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003391 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003392
3393#if defined(DEBUG_SIGNAL)
3394 fprintf(stderr, "do_rt_sigreturn\n");
3395#endif
3396 frame_addr = regs->gregs[15];
3397 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3398 goto badframe;
3399
Aurelien Jarno60e99242010-03-29 02:12:51 +02003400 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
thsc3b5bc82007-12-02 06:31:25 +00003401 sigprocmask(SIG_SETMASK, &blocked, NULL);
3402
Aurelien Jarno60e99242010-03-29 02:12:51 +02003403 if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003404 goto badframe;
3405
3406 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003407 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003408 0, get_sp_from_cpustate(regs)) == -EFAULT)
3409 goto badframe;
3410
3411 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003412 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003413
3414badframe:
3415 unlock_user_struct(frame, frame_addr, 0);
3416 force_sig(TARGET_SIGSEGV);
3417 return 0;
3418}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003419#elif defined(TARGET_MICROBLAZE)
3420
3421struct target_sigcontext {
3422 struct target_pt_regs regs; /* needs to be first */
3423 uint32_t oldmask;
3424};
3425
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003426struct target_stack_t {
3427 abi_ulong ss_sp;
3428 int ss_flags;
3429 unsigned int ss_size;
3430};
3431
3432struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003433 abi_ulong tuc_flags;
3434 abi_ulong tuc_link;
3435 struct target_stack_t tuc_stack;
3436 struct target_sigcontext tuc_mcontext;
3437 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003438};
3439
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003440/* Signal frames. */
3441struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003442 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003443 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3444 uint32_t tramp[2];
3445};
3446
3447struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003448 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003449 struct ucontext uc;
3450 uint32_t tramp[2];
3451};
3452
Andreas Färber05390242012-02-25 03:37:53 +01003453static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003454{
3455 __put_user(env->regs[0], &sc->regs.r0);
3456 __put_user(env->regs[1], &sc->regs.r1);
3457 __put_user(env->regs[2], &sc->regs.r2);
3458 __put_user(env->regs[3], &sc->regs.r3);
3459 __put_user(env->regs[4], &sc->regs.r4);
3460 __put_user(env->regs[5], &sc->regs.r5);
3461 __put_user(env->regs[6], &sc->regs.r6);
3462 __put_user(env->regs[7], &sc->regs.r7);
3463 __put_user(env->regs[8], &sc->regs.r8);
3464 __put_user(env->regs[9], &sc->regs.r9);
3465 __put_user(env->regs[10], &sc->regs.r10);
3466 __put_user(env->regs[11], &sc->regs.r11);
3467 __put_user(env->regs[12], &sc->regs.r12);
3468 __put_user(env->regs[13], &sc->regs.r13);
3469 __put_user(env->regs[14], &sc->regs.r14);
3470 __put_user(env->regs[15], &sc->regs.r15);
3471 __put_user(env->regs[16], &sc->regs.r16);
3472 __put_user(env->regs[17], &sc->regs.r17);
3473 __put_user(env->regs[18], &sc->regs.r18);
3474 __put_user(env->regs[19], &sc->regs.r19);
3475 __put_user(env->regs[20], &sc->regs.r20);
3476 __put_user(env->regs[21], &sc->regs.r21);
3477 __put_user(env->regs[22], &sc->regs.r22);
3478 __put_user(env->regs[23], &sc->regs.r23);
3479 __put_user(env->regs[24], &sc->regs.r24);
3480 __put_user(env->regs[25], &sc->regs.r25);
3481 __put_user(env->regs[26], &sc->regs.r26);
3482 __put_user(env->regs[27], &sc->regs.r27);
3483 __put_user(env->regs[28], &sc->regs.r28);
3484 __put_user(env->regs[29], &sc->regs.r29);
3485 __put_user(env->regs[30], &sc->regs.r30);
3486 __put_user(env->regs[31], &sc->regs.r31);
3487 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3488}
3489
Andreas Färber05390242012-02-25 03:37:53 +01003490static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003491{
3492 __get_user(env->regs[0], &sc->regs.r0);
3493 __get_user(env->regs[1], &sc->regs.r1);
3494 __get_user(env->regs[2], &sc->regs.r2);
3495 __get_user(env->regs[3], &sc->regs.r3);
3496 __get_user(env->regs[4], &sc->regs.r4);
3497 __get_user(env->regs[5], &sc->regs.r5);
3498 __get_user(env->regs[6], &sc->regs.r6);
3499 __get_user(env->regs[7], &sc->regs.r7);
3500 __get_user(env->regs[8], &sc->regs.r8);
3501 __get_user(env->regs[9], &sc->regs.r9);
3502 __get_user(env->regs[10], &sc->regs.r10);
3503 __get_user(env->regs[11], &sc->regs.r11);
3504 __get_user(env->regs[12], &sc->regs.r12);
3505 __get_user(env->regs[13], &sc->regs.r13);
3506 __get_user(env->regs[14], &sc->regs.r14);
3507 __get_user(env->regs[15], &sc->regs.r15);
3508 __get_user(env->regs[16], &sc->regs.r16);
3509 __get_user(env->regs[17], &sc->regs.r17);
3510 __get_user(env->regs[18], &sc->regs.r18);
3511 __get_user(env->regs[19], &sc->regs.r19);
3512 __get_user(env->regs[20], &sc->regs.r20);
3513 __get_user(env->regs[21], &sc->regs.r21);
3514 __get_user(env->regs[22], &sc->regs.r22);
3515 __get_user(env->regs[23], &sc->regs.r23);
3516 __get_user(env->regs[24], &sc->regs.r24);
3517 __get_user(env->regs[25], &sc->regs.r25);
3518 __get_user(env->regs[26], &sc->regs.r26);
3519 __get_user(env->regs[27], &sc->regs.r27);
3520 __get_user(env->regs[28], &sc->regs.r28);
3521 __get_user(env->regs[29], &sc->regs.r29);
3522 __get_user(env->regs[30], &sc->regs.r30);
3523 __get_user(env->regs[31], &sc->regs.r31);
3524 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3525}
3526
3527static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003528 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003529{
3530 abi_ulong sp = env->regs[1];
3531
3532 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3533 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3534
3535 return ((sp - frame_size) & -8UL);
3536}
3537
3538static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003539 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003540{
3541 struct target_signal_frame *frame;
3542 abi_ulong frame_addr;
3543 int err = 0;
3544 int i;
3545
3546 frame_addr = get_sigframe(ka, env, sizeof *frame);
3547 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3548 goto badframe;
3549
3550 /* Save the mask. */
Richard Hendersonf711df62010-11-22 14:57:52 -08003551 err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003552 if (err)
3553 goto badframe;
3554
3555 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3556 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3557 goto badframe;
3558 }
3559
Richard Hendersonf711df62010-11-22 14:57:52 -08003560 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003561
3562 /* Set up to return from userspace. If provided, use a stub
3563 already in userspace. */
3564 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3565 if (ka->sa_flags & TARGET_SA_RESTORER) {
3566 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3567 } else {
3568 uint32_t t;
3569 /* Note, these encodings are _big endian_! */
3570 /* addi r12, r0, __NR_sigreturn */
3571 t = 0x31800000UL | TARGET_NR_sigreturn;
3572 err |= __put_user(t, frame->tramp + 0);
3573 /* brki r14, 0x8 */
3574 t = 0xb9cc0008UL;
3575 err |= __put_user(t, frame->tramp + 1);
3576
3577 /* Return from sighandler will jump to the tramp.
3578 Negative 8 offset because return is rtsd r15, 8 */
3579 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3580 }
3581
3582 if (err)
3583 goto badframe;
3584
3585 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003586 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003587 /* Signal handler args: */
3588 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003589 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003590 /* arg 1: sigcontext */
3591 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003592
3593 /* Offset of 4 to handle microblaze rtid r14, 0 */
3594 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3595
3596 unlock_user_struct(frame, frame_addr, 1);
3597 return;
3598 badframe:
3599 unlock_user_struct(frame, frame_addr, 1);
3600 force_sig(TARGET_SIGSEGV);
3601}
3602
3603static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003604 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003605 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003606{
3607 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3608}
3609
Andreas Färber05390242012-02-25 03:37:53 +01003610long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003611{
3612 struct target_signal_frame *frame;
3613 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003614 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003615 sigset_t set;
3616 int i;
3617
3618 frame_addr = env->regs[R_SP];
3619 /* Make sure the guest isn't playing games. */
3620 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3621 goto badframe;
3622
3623 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003624 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003625 goto badframe;
3626 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3627 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3628 goto badframe;
3629 }
3630 target_to_host_sigset_internal(&set, &target_set);
3631 sigprocmask(SIG_SETMASK, &set, NULL);
3632
Richard Hendersonf711df62010-11-22 14:57:52 -08003633 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003634 /* We got here through a sigreturn syscall, our path back is via an
3635 rtb insn so setup r14 for that. */
3636 env->regs[14] = env->sregs[SR_PC];
3637
3638 unlock_user_struct(frame, frame_addr, 0);
3639 return env->regs[10];
3640 badframe:
3641 unlock_user_struct(frame, frame_addr, 0);
3642 force_sig(TARGET_SIGSEGV);
3643}
3644
Andreas Färber05390242012-02-25 03:37:53 +01003645long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003646{
3647 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3648 return -TARGET_ENOSYS;
3649}
3650
edgar_iglb6d3abd2008-02-28 11:29:27 +00003651#elif defined(TARGET_CRIS)
3652
3653struct target_sigcontext {
3654 struct target_pt_regs regs; /* needs to be first */
3655 uint32_t oldmask;
3656 uint32_t usp; /* usp before stacking this gunk on it */
3657};
3658
3659/* Signal frames. */
3660struct target_signal_frame {
3661 struct target_sigcontext sc;
3662 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003663 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003664};
3665
3666struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003667 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003668 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003669 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003670 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003671 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003672};
3673
Andreas Färber05390242012-02-25 03:37:53 +01003674static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003675{
edgar_igl9664d922008-03-03 22:23:53 +00003676 __put_user(env->regs[0], &sc->regs.r0);
3677 __put_user(env->regs[1], &sc->regs.r1);
3678 __put_user(env->regs[2], &sc->regs.r2);
3679 __put_user(env->regs[3], &sc->regs.r3);
3680 __put_user(env->regs[4], &sc->regs.r4);
3681 __put_user(env->regs[5], &sc->regs.r5);
3682 __put_user(env->regs[6], &sc->regs.r6);
3683 __put_user(env->regs[7], &sc->regs.r7);
3684 __put_user(env->regs[8], &sc->regs.r8);
3685 __put_user(env->regs[9], &sc->regs.r9);
3686 __put_user(env->regs[10], &sc->regs.r10);
3687 __put_user(env->regs[11], &sc->regs.r11);
3688 __put_user(env->regs[12], &sc->regs.r12);
3689 __put_user(env->regs[13], &sc->regs.r13);
3690 __put_user(env->regs[14], &sc->usp);
3691 __put_user(env->regs[15], &sc->regs.acr);
3692 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3693 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3694 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003695}
edgar_igl9664d922008-03-03 22:23:53 +00003696
Andreas Färber05390242012-02-25 03:37:53 +01003697static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003698{
edgar_igl9664d922008-03-03 22:23:53 +00003699 __get_user(env->regs[0], &sc->regs.r0);
3700 __get_user(env->regs[1], &sc->regs.r1);
3701 __get_user(env->regs[2], &sc->regs.r2);
3702 __get_user(env->regs[3], &sc->regs.r3);
3703 __get_user(env->regs[4], &sc->regs.r4);
3704 __get_user(env->regs[5], &sc->regs.r5);
3705 __get_user(env->regs[6], &sc->regs.r6);
3706 __get_user(env->regs[7], &sc->regs.r7);
3707 __get_user(env->regs[8], &sc->regs.r8);
3708 __get_user(env->regs[9], &sc->regs.r9);
3709 __get_user(env->regs[10], &sc->regs.r10);
3710 __get_user(env->regs[11], &sc->regs.r11);
3711 __get_user(env->regs[12], &sc->regs.r12);
3712 __get_user(env->regs[13], &sc->regs.r13);
3713 __get_user(env->regs[14], &sc->usp);
3714 __get_user(env->regs[15], &sc->regs.acr);
3715 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3716 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3717 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003718}
3719
Andreas Färber05390242012-02-25 03:37:53 +01003720static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003721{
edgar_igl9664d922008-03-03 22:23:53 +00003722 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003723 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003724 sp = (env->regs[R_SP] & ~3);
3725 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003726}
3727
pbrook624f7972008-05-31 16:11:38 +00003728static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003729 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003730{
3731 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003732 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003733 int err = 0;
3734 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003735
edgar_igl9664d922008-03-03 22:23:53 +00003736 frame_addr = get_sigframe(env, sizeof *frame);
3737 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003738 goto badframe;
3739
3740 /*
3741 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3742 * use this trampoline anymore but it sets it up for GDB.
3743 * In QEMU, using the trampoline simplifies things a bit so we use it.
3744 *
3745 * This is movu.w __NR_sigreturn, r9; break 13;
3746 */
3747 err |= __put_user(0x9c5f, frame->retcode+0);
3748 err |= __put_user(TARGET_NR_sigreturn,
Stefan Weil8cfc1142014-02-01 09:41:09 +01003749 frame->retcode + 1);
3750 err |= __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003751
3752 /* Save the mask. */
3753 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3754 if (err)
3755 goto badframe;
3756
3757 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3758 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3759 goto badframe;
3760 }
3761
3762 setup_sigcontext(&frame->sc, env);
3763
3764 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003765 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003766 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003767 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003768 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003769 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003770
edgar_igl9664d922008-03-03 22:23:53 +00003771 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003772 return;
3773 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003774 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003775 force_sig(TARGET_SIGSEGV);
3776}
3777
pbrook624f7972008-05-31 16:11:38 +00003778static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003779 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003780 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003781{
3782 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3783}
3784
Andreas Färber05390242012-02-25 03:37:53 +01003785long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003786{
3787 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003788 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003789 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003790 sigset_t set;
3791 int i;
3792
edgar_igl9664d922008-03-03 22:23:53 +00003793 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003794 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003795 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003796 goto badframe;
3797
3798 /* Restore blocked signals */
3799 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3800 goto badframe;
3801 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3802 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3803 goto badframe;
3804 }
3805 target_to_host_sigset_internal(&set, &target_set);
3806 sigprocmask(SIG_SETMASK, &set, NULL);
3807
3808 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003809 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003810 return env->regs[10];
3811 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003812 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003813 force_sig(TARGET_SIGSEGV);
3814}
3815
Andreas Färber05390242012-02-25 03:37:53 +01003816long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003817{
3818 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3819 return -TARGET_ENOSYS;
3820}
thsc3b5bc82007-12-02 06:31:25 +00003821
Jia Liud9627832012-07-20 15:50:52 +08003822#elif defined(TARGET_OPENRISC)
3823
3824struct target_sigcontext {
3825 struct target_pt_regs regs;
3826 abi_ulong oldmask;
3827 abi_ulong usp;
3828};
3829
3830struct target_ucontext {
3831 abi_ulong tuc_flags;
3832 abi_ulong tuc_link;
3833 target_stack_t tuc_stack;
3834 struct target_sigcontext tuc_mcontext;
3835 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3836};
3837
3838struct target_rt_sigframe {
3839 abi_ulong pinfo;
3840 uint64_t puc;
3841 struct target_siginfo info;
3842 struct target_sigcontext sc;
3843 struct target_ucontext uc;
3844 unsigned char retcode[16]; /* trampoline code */
3845};
3846
3847/* This is the asm-generic/ucontext.h version */
3848#if 0
3849static int restore_sigcontext(CPUOpenRISCState *regs,
3850 struct target_sigcontext *sc)
3851{
3852 unsigned int err = 0;
3853 unsigned long old_usp;
3854
3855 /* Alwys make any pending restarted system call return -EINTR */
3856 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3857
3858 /* restore the regs from &sc->regs (same as sc, since regs is first)
3859 * (sc is already checked for VERIFY_READ since the sigframe was
3860 * checked in sys_sigreturn previously)
3861 */
3862
3863 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3864 goto badframe;
3865 }
3866
3867 /* make sure the U-flag is set so user-mode cannot fool us */
3868
3869 regs->sr &= ~SR_SM;
3870
3871 /* restore the old USP as it was before we stacked the sc etc.
3872 * (we cannot just pop the sigcontext since we aligned the sp and
3873 * stuff after pushing it)
3874 */
3875
3876 err |= __get_user(old_usp, &sc->usp);
3877 phx_signal("old_usp 0x%lx", old_usp);
3878
3879 __PHX__ REALLY /* ??? */
3880 wrusp(old_usp);
3881 regs->gpr[1] = old_usp;
3882
3883 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3884 * after this completes, but we don't use that mechanism. maybe we can
3885 * use it now ?
3886 */
3887
3888 return err;
3889
3890badframe:
3891 return 1;
3892}
3893#endif
3894
3895/* Set up a signal frame. */
3896
3897static int setup_sigcontext(struct target_sigcontext *sc,
3898 CPUOpenRISCState *regs,
3899 unsigned long mask)
3900{
3901 int err = 0;
3902 unsigned long usp = regs->gpr[1];
3903
3904 /* copy the regs. they are first in sc so we can use sc directly */
3905
3906 /*err |= copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
3907
3908 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3909 the signal handler. The frametype will be restored to its previous
3910 value in restore_sigcontext. */
3911 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3912
3913 /* then some other stuff */
3914 err |= __put_user(mask, &sc->oldmask);
3915 err |= __put_user(usp, &sc->usp); return err;
3916}
3917
3918static inline unsigned long align_sigframe(unsigned long sp)
3919{
3920 unsigned long i;
3921 i = sp & ~3UL;
3922 return i;
3923}
3924
3925static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3926 CPUOpenRISCState *regs,
3927 size_t frame_size)
3928{
3929 unsigned long sp = regs->gpr[1];
3930 int onsigstack = on_sig_stack(sp);
3931
3932 /* redzone */
3933 /* This is the X/Open sanctioned signal stack switching. */
3934 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3935 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3936 }
3937
3938 sp = align_sigframe(sp - frame_size);
3939
3940 /*
3941 * If we are on the alternate signal stack and would overflow it, don't.
3942 * Return an always-bogus address instead so we will die with SIGSEGV.
3943 */
3944
3945 if (onsigstack && !likely(on_sig_stack(sp))) {
3946 return -1L;
3947 }
3948
3949 return sp;
3950}
3951
3952static void setup_frame(int sig, struct target_sigaction *ka,
3953 target_sigset_t *set, CPUOpenRISCState *env)
3954{
3955 qemu_log("Not implement.\n");
3956}
3957
3958static void setup_rt_frame(int sig, struct target_sigaction *ka,
3959 target_siginfo_t *info,
3960 target_sigset_t *set, CPUOpenRISCState *env)
3961{
3962 int err = 0;
3963 abi_ulong frame_addr;
3964 unsigned long return_ip;
3965 struct target_rt_sigframe *frame;
3966 abi_ulong info_addr, uc_addr;
3967
3968 frame_addr = get_sigframe(ka, env, sizeof *frame);
3969
3970 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3971 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3972 goto give_sigsegv;
3973 }
3974
3975 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
3976 err |= __put_user(info_addr, &frame->pinfo);
3977 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
3978 err |= __put_user(uc_addr, &frame->puc);
3979
3980 if (ka->sa_flags & SA_SIGINFO) {
3981 err |= copy_siginfo_to_user(&frame->info, info);
3982 }
3983 if (err) {
3984 goto give_sigsegv;
3985 }
3986
3987 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
3988 err |= __put_user(0, &frame->uc.tuc_flags);
3989 err |= __put_user(0, &frame->uc.tuc_link);
3990 err |= __put_user(target_sigaltstack_used.ss_sp,
3991 &frame->uc.tuc_stack.ss_sp);
3992 err |= __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3993 err |= __put_user(target_sigaltstack_used.ss_size,
3994 &frame->uc.tuc_stack.ss_size);
3995 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
3996
3997 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3998
3999 if (err) {
4000 goto give_sigsegv;
4001 }
4002
4003 /* trampoline - the desired return ip is the retcode itself */
4004 return_ip = (unsigned long)&frame->retcode;
4005 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
4006 err |= __put_user(0xa960, (short *)(frame->retcode + 0));
4007 err |= __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4008 err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4009 err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
4010
4011 if (err) {
4012 goto give_sigsegv;
4013 }
4014
4015 /* TODO what is the current->exec_domain stuff and invmap ? */
4016
4017 /* Set up registers for signal handler */
4018 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4019 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4020 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4021 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4022 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4023
4024 /* actually move the usp to reflect the stacked frame */
4025 env->gpr[1] = (unsigned long)frame;
4026
4027 return;
4028
4029give_sigsegv:
4030 unlock_user_struct(frame, frame_addr, 1);
4031 if (sig == TARGET_SIGSEGV) {
4032 ka->_sa_handler = TARGET_SIG_DFL;
4033 }
4034 force_sig(TARGET_SIGSEGV);
4035}
4036
4037long do_sigreturn(CPUOpenRISCState *env)
4038{
4039
4040 qemu_log("do_sigreturn: not implemented\n");
4041 return -TARGET_ENOSYS;
4042}
4043
4044long do_rt_sigreturn(CPUOpenRISCState *env)
4045{
4046 qemu_log("do_rt_sigreturn: not implemented\n");
4047 return -TARGET_ENOSYS;
4048}
4049/* TARGET_OPENRISC */
4050
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004051#elif defined(TARGET_S390X)
4052
4053#define __NUM_GPRS 16
4054#define __NUM_FPRS 16
4055#define __NUM_ACRS 16
4056
4057#define S390_SYSCALL_SIZE 2
4058#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4059
4060#define _SIGCONTEXT_NSIG 64
4061#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4062#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4063#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4064#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4065#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4066
4067typedef struct {
4068 target_psw_t psw;
4069 target_ulong gprs[__NUM_GPRS];
4070 unsigned int acrs[__NUM_ACRS];
4071} target_s390_regs_common;
4072
4073typedef struct {
4074 unsigned int fpc;
4075 double fprs[__NUM_FPRS];
4076} target_s390_fp_regs;
4077
4078typedef struct {
4079 target_s390_regs_common regs;
4080 target_s390_fp_regs fpregs;
4081} target_sigregs;
4082
4083struct target_sigcontext {
4084 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4085 target_sigregs *sregs;
4086};
4087
4088typedef struct {
4089 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4090 struct target_sigcontext sc;
4091 target_sigregs sregs;
4092 int signo;
4093 uint8_t retcode[S390_SYSCALL_SIZE];
4094} sigframe;
4095
4096struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004097 target_ulong tuc_flags;
4098 struct target_ucontext *tuc_link;
4099 target_stack_t tuc_stack;
4100 target_sigregs tuc_mcontext;
4101 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004102};
4103
4104typedef struct {
4105 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4106 uint8_t retcode[S390_SYSCALL_SIZE];
4107 struct target_siginfo info;
4108 struct target_ucontext uc;
4109} rt_sigframe;
4110
4111static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004112get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004113{
4114 abi_ulong sp;
4115
4116 /* Default to using normal stack */
4117 sp = env->regs[15];
4118
4119 /* This is the X/Open sanctioned signal stack switching. */
4120 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4121 if (!sas_ss_flags(sp)) {
4122 sp = target_sigaltstack_used.ss_sp +
4123 target_sigaltstack_used.ss_size;
4124 }
4125 }
4126
4127 /* This is the legacy signal stack switching. */
4128 else if (/* FIXME !user_mode(regs) */ 0 &&
4129 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4130 ka->sa_restorer) {
4131 sp = (abi_ulong) ka->sa_restorer;
4132 }
4133
4134 return (sp - frame_size) & -8ul;
4135}
4136
Andreas Färber05390242012-02-25 03:37:53 +01004137static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004138{
4139 int i;
4140 //save_access_regs(current->thread.acrs); FIXME
4141
4142 /* Copy a 'clean' PSW mask to the user to avoid leaking
4143 information about whether PER is currently on. */
4144 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4145 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4146 for (i = 0; i < 16; i++) {
4147 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4148 }
4149 for (i = 0; i < 16; i++) {
4150 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4151 }
4152 /*
4153 * We have to store the fp registers to current->thread.fp_regs
4154 * to merge them with the emulated registers.
4155 */
4156 //save_fp_regs(&current->thread.fp_regs); FIXME
4157 for (i = 0; i < 16; i++) {
4158 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4159 }
4160}
4161
4162static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004163 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004164{
4165 sigframe *frame;
4166 abi_ulong frame_addr;
4167
4168 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4169 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4170 (unsigned long long)frame_addr);
4171 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4172 goto give_sigsegv;
4173 }
4174
4175 qemu_log("%s: 1\n", __FUNCTION__);
4176 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
4177 goto give_sigsegv;
4178 }
4179
4180 save_sigregs(env, &frame->sregs);
4181
4182 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4183 (abi_ulong *)&frame->sc.sregs);
4184
4185 /* Set up to return from userspace. If provided, use a stub
4186 already in userspace. */
4187 if (ka->sa_flags & TARGET_SA_RESTORER) {
4188 env->regs[14] = (unsigned long)
4189 ka->sa_restorer | PSW_ADDR_AMODE;
4190 } else {
4191 env->regs[14] = (unsigned long)
4192 frame->retcode | PSW_ADDR_AMODE;
4193 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4194 (uint16_t *)(frame->retcode)))
4195 goto give_sigsegv;
4196 }
4197
4198 /* Set up backchain. */
4199 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4200 goto give_sigsegv;
4201 }
4202
4203 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004204 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004205 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4206
4207 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004208 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004209
4210 /* We forgot to include these in the sigcontext.
4211 To avoid breaking binary compatibility, they are passed as args. */
4212 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4213 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4214
4215 /* Place signal number on stack to allow backtrace from handler. */
4216 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4217 goto give_sigsegv;
4218 }
4219 unlock_user_struct(frame, frame_addr, 1);
4220 return;
4221
4222give_sigsegv:
4223 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4224 unlock_user_struct(frame, frame_addr, 1);
4225 force_sig(TARGET_SIGSEGV);
4226}
4227
4228static void setup_rt_frame(int sig, struct target_sigaction *ka,
4229 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004230 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004231{
4232 int i;
4233 rt_sigframe *frame;
4234 abi_ulong frame_addr;
4235
4236 frame_addr = get_sigframe(ka, env, sizeof *frame);
4237 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4238 (unsigned long long)frame_addr);
4239 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4240 goto give_sigsegv;
4241 }
4242
4243 qemu_log("%s: 1\n", __FUNCTION__);
4244 if (copy_siginfo_to_user(&frame->info, info)) {
4245 goto give_sigsegv;
4246 }
4247
4248 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004249 __put_user(0, &frame->uc.tuc_flags);
4250 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4251 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004252 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004253 &frame->uc.tuc_stack.ss_flags);
4254 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4255 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004256 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4257 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004258 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004259 }
4260
4261 /* Set up to return from userspace. If provided, use a stub
4262 already in userspace. */
4263 if (ka->sa_flags & TARGET_SA_RESTORER) {
4264 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4265 } else {
4266 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4267 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4268 (uint16_t *)(frame->retcode))) {
4269 goto give_sigsegv;
4270 }
4271 }
4272
4273 /* Set up backchain. */
4274 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4275 goto give_sigsegv;
4276 }
4277
4278 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004279 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004280 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4281
4282 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004283 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4284 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004285 return;
4286
4287give_sigsegv:
4288 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4289 unlock_user_struct(frame, frame_addr, 1);
4290 force_sig(TARGET_SIGSEGV);
4291}
4292
4293static int
Andreas Färber05390242012-02-25 03:37:53 +01004294restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004295{
4296 int err = 0;
4297 int i;
4298
4299 for (i = 0; i < 16; i++) {
4300 err |= __get_user(env->regs[i], &sc->regs.gprs[i]);
4301 }
4302
4303 err |= __get_user(env->psw.mask, &sc->regs.psw.mask);
4304 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4305 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4306 (unsigned long long)env->psw.addr);
4307 err |= __get_user(env->psw.addr, &sc->regs.psw.addr);
4308 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4309
4310 for (i = 0; i < 16; i++) {
4311 err |= __get_user(env->aregs[i], &sc->regs.acrs[i]);
4312 }
4313 for (i = 0; i < 16; i++) {
4314 err |= __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
4315 }
4316
4317 return err;
4318}
4319
Andreas Färber05390242012-02-25 03:37:53 +01004320long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004321{
4322 sigframe *frame;
4323 abi_ulong frame_addr = env->regs[15];
4324 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4325 (unsigned long long)frame_addr);
4326 target_sigset_t target_set;
4327 sigset_t set;
4328
4329 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4330 goto badframe;
4331 }
4332 if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
4333 goto badframe;
4334 }
4335
4336 target_to_host_sigset_internal(&set, &target_set);
4337 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4338
4339 if (restore_sigregs(env, &frame->sregs)) {
4340 goto badframe;
4341 }
4342
4343 unlock_user_struct(frame, frame_addr, 0);
4344 return env->regs[2];
4345
4346badframe:
4347 unlock_user_struct(frame, frame_addr, 0);
4348 force_sig(TARGET_SIGSEGV);
4349 return 0;
4350}
4351
Andreas Färber05390242012-02-25 03:37:53 +01004352long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004353{
4354 rt_sigframe *frame;
4355 abi_ulong frame_addr = env->regs[15];
4356 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4357 (unsigned long long)frame_addr);
4358 sigset_t set;
4359
4360 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4361 goto badframe;
4362 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004363 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004364
4365 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4366
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004367 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004368 goto badframe;
4369 }
4370
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004371 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004372 get_sp_from_cpustate(env)) == -EFAULT) {
4373 goto badframe;
4374 }
4375 unlock_user_struct(frame, frame_addr, 0);
4376 return env->regs[2];
4377
4378badframe:
4379 unlock_user_struct(frame, frame_addr, 0);
4380 force_sig(TARGET_SIGSEGV);
4381 return 0;
4382}
4383
Nathan Froydbcd49332009-05-12 19:13:18 -07004384#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4385
4386/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4387 the signal handling is different enough that we haven't implemented
4388 support for PPC64 yet. Hence the restriction above.
4389
4390 There are various #if'd blocks for code for TARGET_PPC64. These
4391 blocks should go away so that we can successfully run 32-bit and
4392 64-bit binaries on a QEMU configured for PPC64. */
4393
4394/* Size of dummy stack frame allocated when calling signal handler.
4395 See arch/powerpc/include/asm/ptrace.h. */
4396#if defined(TARGET_PPC64)
4397#define SIGNAL_FRAMESIZE 128
4398#else
4399#define SIGNAL_FRAMESIZE 64
4400#endif
4401
4402/* See arch/powerpc/include/asm/sigcontext.h. */
4403struct target_sigcontext {
4404 target_ulong _unused[4];
4405 int32_t signal;
4406#if defined(TARGET_PPC64)
4407 int32_t pad0;
4408#endif
4409 target_ulong handler;
4410 target_ulong oldmask;
4411 target_ulong regs; /* struct pt_regs __user * */
4412 /* TODO: PPC64 includes extra bits here. */
4413};
4414
4415/* Indices for target_mcontext.mc_gregs, below.
4416 See arch/powerpc/include/asm/ptrace.h for details. */
4417enum {
4418 TARGET_PT_R0 = 0,
4419 TARGET_PT_R1 = 1,
4420 TARGET_PT_R2 = 2,
4421 TARGET_PT_R3 = 3,
4422 TARGET_PT_R4 = 4,
4423 TARGET_PT_R5 = 5,
4424 TARGET_PT_R6 = 6,
4425 TARGET_PT_R7 = 7,
4426 TARGET_PT_R8 = 8,
4427 TARGET_PT_R9 = 9,
4428 TARGET_PT_R10 = 10,
4429 TARGET_PT_R11 = 11,
4430 TARGET_PT_R12 = 12,
4431 TARGET_PT_R13 = 13,
4432 TARGET_PT_R14 = 14,
4433 TARGET_PT_R15 = 15,
4434 TARGET_PT_R16 = 16,
4435 TARGET_PT_R17 = 17,
4436 TARGET_PT_R18 = 18,
4437 TARGET_PT_R19 = 19,
4438 TARGET_PT_R20 = 20,
4439 TARGET_PT_R21 = 21,
4440 TARGET_PT_R22 = 22,
4441 TARGET_PT_R23 = 23,
4442 TARGET_PT_R24 = 24,
4443 TARGET_PT_R25 = 25,
4444 TARGET_PT_R26 = 26,
4445 TARGET_PT_R27 = 27,
4446 TARGET_PT_R28 = 28,
4447 TARGET_PT_R29 = 29,
4448 TARGET_PT_R30 = 30,
4449 TARGET_PT_R31 = 31,
4450 TARGET_PT_NIP = 32,
4451 TARGET_PT_MSR = 33,
4452 TARGET_PT_ORIG_R3 = 34,
4453 TARGET_PT_CTR = 35,
4454 TARGET_PT_LNK = 36,
4455 TARGET_PT_XER = 37,
4456 TARGET_PT_CCR = 38,
4457 /* Yes, there are two registers with #39. One is 64-bit only. */
4458 TARGET_PT_MQ = 39,
4459 TARGET_PT_SOFTE = 39,
4460 TARGET_PT_TRAP = 40,
4461 TARGET_PT_DAR = 41,
4462 TARGET_PT_DSISR = 42,
4463 TARGET_PT_RESULT = 43,
4464 TARGET_PT_REGS_COUNT = 44
4465};
4466
4467/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4468 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4469struct target_mcontext {
4470 target_ulong mc_gregs[48];
4471 /* Includes fpscr. */
4472 uint64_t mc_fregs[33];
4473 target_ulong mc_pad[2];
4474 /* We need to handle Altivec and SPE at the same time, which no
4475 kernel needs to do. Fortunately, the kernel defines this bit to
4476 be Altivec-register-large all the time, rather than trying to
4477 twiddle it based on the specific platform. */
4478 union {
4479 /* SPE vector registers. One extra for SPEFSCR. */
4480 uint32_t spe[33];
4481 /* Altivec vector registers. The packing of VSCR and VRSAVE
4482 varies depending on whether we're PPC64 or not: PPC64 splits
4483 them apart; PPC32 stuffs them together. */
4484#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004485#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004486#else
malc3efa9a62009-07-18 13:10:12 +04004487#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004488#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004489 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004490#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004491 } mc_vregs __attribute__((__aligned__(16)));
4492};
4493
4494struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004495 target_ulong tuc_flags;
4496 target_ulong tuc_link; /* struct ucontext __user * */
4497 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004498#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004499 int32_t tuc_pad[7];
4500 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004501 points to uc_mcontext field */
4502#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004503 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004504#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004505 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004506 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004507#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004508 int32_t tuc_maskext[30];
4509 int32_t tuc_pad2[3];
4510 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004511#endif
4512};
4513
4514/* See arch/powerpc/kernel/signal_32.c. */
4515struct target_sigframe {
4516 struct target_sigcontext sctx;
4517 struct target_mcontext mctx;
4518 int32_t abigap[56];
4519};
4520
4521struct target_rt_sigframe {
4522 struct target_siginfo info;
4523 struct target_ucontext uc;
4524 int32_t abigap[56];
4525};
4526
4527/* We use the mc_pad field for the signal return trampoline. */
4528#define tramp mc_pad
4529
4530/* See arch/powerpc/kernel/signal.c. */
4531static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004532 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004533 int frame_size)
4534{
4535 target_ulong oldsp, newsp;
4536
4537 oldsp = env->gpr[1];
4538
4539 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004540 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004541 oldsp = (target_sigaltstack_used.ss_sp
4542 + target_sigaltstack_used.ss_size);
4543 }
4544
4545 newsp = (oldsp - frame_size) & ~0xFUL;
4546
4547 return newsp;
4548}
4549
Andreas Färber05390242012-02-25 03:37:53 +01004550static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004551 int sigret)
4552{
4553 target_ulong msr = env->msr;
4554 int i;
4555 target_ulong ccr = 0;
4556
4557 /* In general, the kernel attempts to be intelligent about what it
4558 needs to save for Altivec/FP/SPE registers. We don't care that
4559 much, so we just go ahead and save everything. */
4560
4561 /* Save general registers. */
4562 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4563 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4564 return 1;
4565 }
4566 }
4567 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4568 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4569 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4570 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4571 return 1;
4572
4573 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4574 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4575 }
4576 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4577 return 1;
4578
4579 /* Save Altivec registers if necessary. */
4580 if (env->insns_flags & PPC_ALTIVEC) {
4581 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004582 ppc_avr_t *avr = &env->avr[i];
4583 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004584
4585 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4586 __put_user(avr->u64[1], &vreg->u64[1])) {
4587 return 1;
4588 }
4589 }
4590 /* Set MSR_VR in the saved MSR value to indicate that
4591 frame->mc_vregs contains valid data. */
4592 msr |= MSR_VR;
4593 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4594 &frame->mc_vregs.altivec[32].u32[3]))
4595 return 1;
4596 }
4597
4598 /* Save floating point registers. */
4599 if (env->insns_flags & PPC_FLOAT) {
4600 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4601 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4602 return 1;
4603 }
4604 }
4605 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4606 return 1;
4607 }
4608
4609 /* Save SPE registers. The kernel only saves the high half. */
4610 if (env->insns_flags & PPC_SPE) {
4611#if defined(TARGET_PPC64)
4612 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4613 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4614 return 1;
4615 }
4616 }
4617#else
4618 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4619 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4620 return 1;
4621 }
4622 }
4623#endif
4624 /* Set MSR_SPE in the saved MSR value to indicate that
4625 frame->mc_vregs contains valid data. */
4626 msr |= MSR_SPE;
4627 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4628 return 1;
4629 }
4630
4631 /* Store MSR. */
4632 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4633 return 1;
4634
4635 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4636 if (sigret) {
4637 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4638 __put_user(0x44000002UL, &frame->tramp[1])) {
4639 return 1;
4640 }
4641 }
4642
4643 return 0;
4644}
4645
Andreas Färber05390242012-02-25 03:37:53 +01004646static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004647 struct target_mcontext *frame, int sig)
4648{
4649 target_ulong save_r2 = 0;
4650 target_ulong msr;
4651 target_ulong ccr;
4652
4653 int i;
4654
4655 if (!sig) {
4656 save_r2 = env->gpr[2];
4657 }
4658
4659 /* Restore general registers. */
4660 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4661 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4662 return 1;
4663 }
4664 }
4665 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4666 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4667 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4668 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4669 return 1;
4670 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4671 return 1;
4672
4673 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4674 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4675 }
4676
4677 if (!sig) {
4678 env->gpr[2] = save_r2;
4679 }
4680 /* Restore MSR. */
4681 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4682 return 1;
4683
4684 /* If doing signal return, restore the previous little-endian mode. */
4685 if (sig)
4686 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4687
4688 /* Restore Altivec registers if necessary. */
4689 if (env->insns_flags & PPC_ALTIVEC) {
4690 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004691 ppc_avr_t *avr = &env->avr[i];
4692 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004693
4694 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4695 __get_user(avr->u64[1], &vreg->u64[1])) {
4696 return 1;
4697 }
4698 }
4699 /* Set MSR_VEC in the saved MSR value to indicate that
4700 frame->mc_vregs contains valid data. */
4701 if (__get_user(env->spr[SPR_VRSAVE],
4702 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4703 return 1;
4704 }
4705
4706 /* Restore floating point registers. */
4707 if (env->insns_flags & PPC_FLOAT) {
4708 uint64_t fpscr;
4709 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4710 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4711 return 1;
4712 }
4713 }
4714 if (__get_user(fpscr, &frame->mc_fregs[32]))
4715 return 1;
4716 env->fpscr = (uint32_t) fpscr;
4717 }
4718
4719 /* Save SPE registers. The kernel only saves the high half. */
4720 if (env->insns_flags & PPC_SPE) {
4721#if defined(TARGET_PPC64)
4722 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4723 uint32_t hi;
4724
4725 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4726 return 1;
4727 }
4728 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4729 }
4730#else
4731 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4732 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4733 return 1;
4734 }
4735 }
4736#endif
4737 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4738 return 1;
4739 }
4740
4741 return 0;
4742}
4743
4744static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004745 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004746{
4747 struct target_sigframe *frame;
4748 struct target_sigcontext *sc;
4749 target_ulong frame_addr, newsp;
4750 int err = 0;
4751 int signal;
4752
4753 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4754 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4755 goto sigsegv;
4756 sc = &frame->sctx;
4757
4758 signal = current_exec_domain_sig(sig);
4759
Samuel Seaybeb526b2013-01-02 10:53:46 +00004760 err |= __put_user(ka->_sa_handler, &sc->handler);
Nathan Froydbcd49332009-05-12 19:13:18 -07004761 err |= __put_user(set->sig[0], &sc->oldmask);
4762#if defined(TARGET_PPC64)
4763 err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
4764#else
4765 err |= __put_user(set->sig[1], &sc->_unused[3]);
4766#endif
4767 err |= __put_user(h2g(&frame->mctx), &sc->regs);
4768 err |= __put_user(sig, &sc->signal);
4769
4770 /* Save user regs. */
4771 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4772
4773 /* The kernel checks for the presence of a VDSO here. We don't
4774 emulate a vdso, so use a sigreturn system call. */
4775 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4776
4777 /* Turn off all fp exceptions. */
4778 env->fpscr = 0;
4779
4780 /* Create a stack frame for the caller of the handler. */
4781 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004782 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004783
4784 if (err)
4785 goto sigsegv;
4786
4787 /* Set up registers for signal handler. */
4788 env->gpr[1] = newsp;
4789 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004790 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004791 env->nip = (target_ulong) ka->_sa_handler;
4792 /* Signal handlers are entered in big-endian mode. */
4793 env->msr &= ~MSR_LE;
4794
4795 unlock_user_struct(frame, frame_addr, 1);
4796 return;
4797
4798sigsegv:
4799 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004800 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004801 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004802}
4803
4804static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004805 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004806 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004807{
4808 struct target_rt_sigframe *rt_sf;
4809 struct target_mcontext *frame;
4810 target_ulong rt_sf_addr, newsp = 0;
4811 int i, err = 0;
4812 int signal;
4813
4814 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4815 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4816 goto sigsegv;
4817
4818 signal = current_exec_domain_sig(sig);
4819
4820 err |= copy_siginfo_to_user(&rt_sf->info, info);
4821
Aurelien Jarno60e99242010-03-29 02:12:51 +02004822 err |= __put_user(0, &rt_sf->uc.tuc_flags);
4823 err |= __put_user(0, &rt_sf->uc.tuc_link);
Nathan Froydbcd49332009-05-12 19:13:18 -07004824 err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004825 &rt_sf->uc.tuc_stack.ss_sp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004826 err |= __put_user(sas_ss_flags(env->gpr[1]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02004827 &rt_sf->uc.tuc_stack.ss_flags);
Nathan Froydbcd49332009-05-12 19:13:18 -07004828 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004829 &rt_sf->uc.tuc_stack.ss_size);
4830 err |= __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4831 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004832 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004833 err |= __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004834 }
4835
Aurelien Jarno60e99242010-03-29 02:12:51 +02004836 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004837 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4838
4839 /* The kernel checks for the presence of a VDSO here. We don't
4840 emulate a vdso, so use a sigreturn system call. */
4841 env->lr = (target_ulong) h2g(frame->tramp);
4842
4843 /* Turn off all fp exceptions. */
4844 env->fpscr = 0;
4845
4846 /* Create a stack frame for the caller of the handler. */
4847 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
4848 err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
4849
4850 if (err)
4851 goto sigsegv;
4852
4853 /* Set up registers for signal handler. */
4854 env->gpr[1] = newsp;
4855 env->gpr[3] = (target_ulong) signal;
4856 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4857 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4858 env->gpr[6] = (target_ulong) h2g(rt_sf);
4859 env->nip = (target_ulong) ka->_sa_handler;
4860 /* Signal handlers are entered in big-endian mode. */
4861 env->msr &= ~MSR_LE;
4862
4863 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4864 return;
4865
4866sigsegv:
4867 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004868 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004869 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004870
4871}
4872
Andreas Färber05390242012-02-25 03:37:53 +01004873long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004874{
4875 struct target_sigcontext *sc = NULL;
4876 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004877 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004878 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004879 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004880
4881 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4882 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4883 goto sigsegv;
4884
4885#if defined(TARGET_PPC64)
4886 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4887#else
4888 if(__get_user(set.sig[0], &sc->oldmask) ||
4889 __get_user(set.sig[1], &sc->_unused[3]))
4890 goto sigsegv;
4891#endif
4892 target_to_host_sigset_internal(&blocked, &set);
4893 sigprocmask(SIG_SETMASK, &blocked, NULL);
4894
4895 if (__get_user(sr_addr, &sc->regs))
4896 goto sigsegv;
4897 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4898 goto sigsegv;
4899 if (restore_user_regs(env, sr, 1))
4900 goto sigsegv;
4901
4902 unlock_user_struct(sr, sr_addr, 1);
4903 unlock_user_struct(sc, sc_addr, 1);
4904 return -TARGET_QEMU_ESIGRETURN;
4905
4906sigsegv:
4907 unlock_user_struct(sr, sr_addr, 1);
4908 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004909 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004910 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004911 return 0;
4912}
4913
4914/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004915static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004916{
4917 struct target_mcontext *mcp;
4918 target_ulong mcp_addr;
4919 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004920 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004921
Aurelien Jarno60e99242010-03-29 02:12:51 +02004922 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004923 sizeof (set)))
4924 return 1;
4925
4926#if defined(TARGET_PPC64)
4927 fprintf (stderr, "do_setcontext: not implemented\n");
4928 return 0;
4929#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004930 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004931 return 1;
4932
4933 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4934 return 1;
4935
4936 target_to_host_sigset_internal(&blocked, &set);
4937 sigprocmask(SIG_SETMASK, &blocked, NULL);
4938 if (restore_user_regs(env, mcp, sig))
4939 goto sigsegv;
4940
4941 unlock_user_struct(mcp, mcp_addr, 1);
4942 return 0;
4943
4944sigsegv:
4945 unlock_user_struct(mcp, mcp_addr, 1);
4946 return 1;
4947#endif
4948}
4949
Andreas Färber05390242012-02-25 03:37:53 +01004950long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004951{
4952 struct target_rt_sigframe *rt_sf = NULL;
4953 target_ulong rt_sf_addr;
4954
4955 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4956 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4957 goto sigsegv;
4958
4959 if (do_setcontext(&rt_sf->uc, env, 1))
4960 goto sigsegv;
4961
4962 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004963 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004964 0, env->gpr[1]);
4965
4966 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4967 return -TARGET_QEMU_ESIGRETURN;
4968
4969sigsegv:
4970 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004971 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004972 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004973 return 0;
4974}
4975
Laurent Vivier492a8742009-08-03 16:12:17 +02004976#elif defined(TARGET_M68K)
4977
4978struct target_sigcontext {
4979 abi_ulong sc_mask;
4980 abi_ulong sc_usp;
4981 abi_ulong sc_d0;
4982 abi_ulong sc_d1;
4983 abi_ulong sc_a0;
4984 abi_ulong sc_a1;
4985 unsigned short sc_sr;
4986 abi_ulong sc_pc;
4987};
4988
4989struct target_sigframe
4990{
4991 abi_ulong pretcode;
4992 int sig;
4993 int code;
4994 abi_ulong psc;
4995 char retcode[8];
4996 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4997 struct target_sigcontext sc;
4998};
Laurent Vivier71811552009-08-03 16:12:18 +02004999
Anthony Liguoric227f092009-10-01 16:12:16 -05005000typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005001#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005002typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005003
5004typedef struct target_fpregset {
5005 int f_fpcntl[3];
5006 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005007} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005008
5009struct target_mcontext {
5010 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005011 target_gregset_t gregs;
5012 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005013};
5014
5015#define TARGET_MCONTEXT_VERSION 2
5016
5017struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005018 abi_ulong tuc_flags;
5019 abi_ulong tuc_link;
5020 target_stack_t tuc_stack;
5021 struct target_mcontext tuc_mcontext;
5022 abi_long tuc_filler[80];
5023 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005024};
5025
5026struct target_rt_sigframe
5027{
5028 abi_ulong pretcode;
5029 int sig;
5030 abi_ulong pinfo;
5031 abi_ulong puc;
5032 char retcode[8];
5033 struct target_siginfo info;
5034 struct target_ucontext uc;
5035};
Laurent Vivier492a8742009-08-03 16:12:17 +02005036
5037static int
Andreas Färber05390242012-02-25 03:37:53 +01005038setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
5039 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005040{
5041 int err = 0;
5042
5043 err |= __put_user(mask, &sc->sc_mask);
5044 err |= __put_user(env->aregs[7], &sc->sc_usp);
5045 err |= __put_user(env->dregs[0], &sc->sc_d0);
5046 err |= __put_user(env->dregs[1], &sc->sc_d1);
5047 err |= __put_user(env->aregs[0], &sc->sc_a0);
5048 err |= __put_user(env->aregs[1], &sc->sc_a1);
5049 err |= __put_user(env->sr, &sc->sc_sr);
5050 err |= __put_user(env->pc, &sc->sc_pc);
5051
5052 return err;
5053}
5054
5055static int
Andreas Färber05390242012-02-25 03:37:53 +01005056restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005057{
5058 int err = 0;
5059 int temp;
5060
5061 err |= __get_user(env->aregs[7], &sc->sc_usp);
5062 err |= __get_user(env->dregs[1], &sc->sc_d1);
5063 err |= __get_user(env->aregs[0], &sc->sc_a0);
5064 err |= __get_user(env->aregs[1], &sc->sc_a1);
5065 err |= __get_user(env->pc, &sc->sc_pc);
5066 err |= __get_user(temp, &sc->sc_sr);
5067 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5068
5069 *pd0 = tswapl(sc->sc_d0);
5070
5071 return err;
5072}
5073
5074/*
5075 * Determine which stack to use..
5076 */
5077static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005078get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5079 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005080{
5081 unsigned long sp;
5082
5083 sp = regs->aregs[7];
5084
5085 /* This is the X/Open sanctioned signal stack switching. */
5086 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5087 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5088 }
5089
5090 return ((sp - frame_size) & -8UL);
5091}
5092
5093static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005094 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005095{
5096 struct target_sigframe *frame;
5097 abi_ulong frame_addr;
5098 abi_ulong retcode_addr;
5099 abi_ulong sc_addr;
5100 int err = 0;
5101 int i;
5102
5103 frame_addr = get_sigframe(ka, env, sizeof *frame);
5104 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5105 goto give_sigsegv;
5106
5107 err |= __put_user(sig, &frame->sig);
5108
5109 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
5110 err |= __put_user(sc_addr, &frame->psc);
5111
5112 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
5113 if (err)
5114 goto give_sigsegv;
5115
5116 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5117 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
5118 goto give_sigsegv;
5119 }
5120
5121 /* Set up to return from userspace. */
5122
5123 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5124 err |= __put_user(retcode_addr, &frame->pretcode);
5125
5126 /* moveq #,d0; trap #0 */
5127
5128 err |= __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
5129 (long *)(frame->retcode));
5130
5131 if (err)
5132 goto give_sigsegv;
5133
5134 /* Set up to return from userspace */
5135
5136 env->aregs[7] = frame_addr;
5137 env->pc = ka->_sa_handler;
5138
5139 unlock_user_struct(frame, frame_addr, 1);
5140 return;
5141
5142give_sigsegv:
5143 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005144 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005145}
5146
Laurent Vivier71811552009-08-03 16:12:18 +02005147static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005148 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005149{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005150 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005151 int err;
5152
Aurelien Jarno60e99242010-03-29 02:12:51 +02005153 err = __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005154 err |= __put_user(env->dregs[0], &gregs[0]);
5155 err |= __put_user(env->dregs[1], &gregs[1]);
5156 err |= __put_user(env->dregs[2], &gregs[2]);
5157 err |= __put_user(env->dregs[3], &gregs[3]);
5158 err |= __put_user(env->dregs[4], &gregs[4]);
5159 err |= __put_user(env->dregs[5], &gregs[5]);
5160 err |= __put_user(env->dregs[6], &gregs[6]);
5161 err |= __put_user(env->dregs[7], &gregs[7]);
5162 err |= __put_user(env->aregs[0], &gregs[8]);
5163 err |= __put_user(env->aregs[1], &gregs[9]);
5164 err |= __put_user(env->aregs[2], &gregs[10]);
5165 err |= __put_user(env->aregs[3], &gregs[11]);
5166 err |= __put_user(env->aregs[4], &gregs[12]);
5167 err |= __put_user(env->aregs[5], &gregs[13]);
5168 err |= __put_user(env->aregs[6], &gregs[14]);
5169 err |= __put_user(env->aregs[7], &gregs[15]);
5170 err |= __put_user(env->pc, &gregs[16]);
5171 err |= __put_user(env->sr, &gregs[17]);
5172
5173 return err;
5174}
5175
Andreas Färber05390242012-02-25 03:37:53 +01005176static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005177 struct target_ucontext *uc,
5178 int *pd0)
5179{
5180 int temp;
5181 int err;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005182 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005183
Aurelien Jarno60e99242010-03-29 02:12:51 +02005184 err = __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005185 if (temp != TARGET_MCONTEXT_VERSION)
5186 goto badframe;
5187
5188 /* restore passed registers */
5189 err |= __get_user(env->dregs[0], &gregs[0]);
5190 err |= __get_user(env->dregs[1], &gregs[1]);
5191 err |= __get_user(env->dregs[2], &gregs[2]);
5192 err |= __get_user(env->dregs[3], &gregs[3]);
5193 err |= __get_user(env->dregs[4], &gregs[4]);
5194 err |= __get_user(env->dregs[5], &gregs[5]);
5195 err |= __get_user(env->dregs[6], &gregs[6]);
5196 err |= __get_user(env->dregs[7], &gregs[7]);
5197 err |= __get_user(env->aregs[0], &gregs[8]);
5198 err |= __get_user(env->aregs[1], &gregs[9]);
5199 err |= __get_user(env->aregs[2], &gregs[10]);
5200 err |= __get_user(env->aregs[3], &gregs[11]);
5201 err |= __get_user(env->aregs[4], &gregs[12]);
5202 err |= __get_user(env->aregs[5], &gregs[13]);
5203 err |= __get_user(env->aregs[6], &gregs[14]);
5204 err |= __get_user(env->aregs[7], &gregs[15]);
5205 err |= __get_user(env->pc, &gregs[16]);
5206 err |= __get_user(temp, &gregs[17]);
5207 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5208
5209 *pd0 = env->dregs[0];
5210 return err;
5211
5212badframe:
5213 return 1;
5214}
5215
Laurent Vivier492a8742009-08-03 16:12:17 +02005216static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005217 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005218 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005219{
Laurent Vivier71811552009-08-03 16:12:18 +02005220 struct target_rt_sigframe *frame;
5221 abi_ulong frame_addr;
5222 abi_ulong retcode_addr;
5223 abi_ulong info_addr;
5224 abi_ulong uc_addr;
5225 int err = 0;
5226 int i;
5227
5228 frame_addr = get_sigframe(ka, env, sizeof *frame);
5229 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5230 goto give_sigsegv;
5231
5232 err |= __put_user(sig, &frame->sig);
5233
5234 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
5235 err |= __put_user(info_addr, &frame->pinfo);
5236
5237 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
5238 err |= __put_user(uc_addr, &frame->puc);
5239
5240 err |= copy_siginfo_to_user(&frame->info, info);
5241
5242 /* Create the ucontext */
5243
Aurelien Jarno60e99242010-03-29 02:12:51 +02005244 err |= __put_user(0, &frame->uc.tuc_flags);
5245 err |= __put_user(0, &frame->uc.tuc_link);
Laurent Vivier71811552009-08-03 16:12:18 +02005246 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005247 &frame->uc.tuc_stack.ss_sp);
Laurent Vivier71811552009-08-03 16:12:18 +02005248 err |= __put_user(sas_ss_flags(env->aregs[7]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005249 &frame->uc.tuc_stack.ss_flags);
Laurent Vivier71811552009-08-03 16:12:18 +02005250 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005251 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005252 err |= target_rt_setup_ucontext(&frame->uc, env);
5253
5254 if (err)
5255 goto give_sigsegv;
5256
5257 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005258 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005259 goto give_sigsegv;
5260 }
5261
5262 /* Set up to return from userspace. */
5263
5264 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5265 err |= __put_user(retcode_addr, &frame->pretcode);
5266
5267 /* moveq #,d0; notb d0; trap #0 */
5268
5269 err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5270 (long *)(frame->retcode + 0));
5271 err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
5272
5273 if (err)
5274 goto give_sigsegv;
5275
5276 /* Set up to return from userspace */
5277
5278 env->aregs[7] = frame_addr;
5279 env->pc = ka->_sa_handler;
5280
5281 unlock_user_struct(frame, frame_addr, 1);
5282 return;
5283
5284give_sigsegv:
5285 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005286 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005287}
5288
Andreas Färber05390242012-02-25 03:37:53 +01005289long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005290{
5291 struct target_sigframe *frame;
5292 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005293 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005294 sigset_t set;
5295 int d0, i;
5296
5297 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5298 goto badframe;
5299
5300 /* set blocked signals */
5301
5302 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
5303 goto badframe;
5304
5305 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5306 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
5307 goto badframe;
5308 }
5309
5310 target_to_host_sigset_internal(&set, &target_set);
5311 sigprocmask(SIG_SETMASK, &set, NULL);
5312
5313 /* restore registers */
5314
5315 if (restore_sigcontext(env, &frame->sc, &d0))
5316 goto badframe;
5317
5318 unlock_user_struct(frame, frame_addr, 0);
5319 return d0;
5320
5321badframe:
5322 unlock_user_struct(frame, frame_addr, 0);
5323 force_sig(TARGET_SIGSEGV);
5324 return 0;
5325}
5326
Andreas Färber05390242012-02-25 03:37:53 +01005327long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005328{
Laurent Vivier71811552009-08-03 16:12:18 +02005329 struct target_rt_sigframe *frame;
5330 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005331 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005332 sigset_t set;
5333 int d0;
5334
5335 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5336 goto badframe;
5337
5338 target_to_host_sigset_internal(&set, &target_set);
5339 sigprocmask(SIG_SETMASK, &set, NULL);
5340
5341 /* restore registers */
5342
5343 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5344 goto badframe;
5345
5346 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005347 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005348 0, get_sp_from_cpustate(env)) == -EFAULT)
5349 goto badframe;
5350
5351 unlock_user_struct(frame, frame_addr, 0);
5352 return d0;
5353
5354badframe:
5355 unlock_user_struct(frame, frame_addr, 0);
5356 force_sig(TARGET_SIGSEGV);
5357 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005358}
5359
Richard Henderson6049f4f2009-12-27 18:30:03 -08005360#elif defined(TARGET_ALPHA)
5361
5362struct target_sigcontext {
5363 abi_long sc_onstack;
5364 abi_long sc_mask;
5365 abi_long sc_pc;
5366 abi_long sc_ps;
5367 abi_long sc_regs[32];
5368 abi_long sc_ownedfp;
5369 abi_long sc_fpregs[32];
5370 abi_ulong sc_fpcr;
5371 abi_ulong sc_fp_control;
5372 abi_ulong sc_reserved1;
5373 abi_ulong sc_reserved2;
5374 abi_ulong sc_ssize;
5375 abi_ulong sc_sbase;
5376 abi_ulong sc_traparg_a0;
5377 abi_ulong sc_traparg_a1;
5378 abi_ulong sc_traparg_a2;
5379 abi_ulong sc_fp_trap_pc;
5380 abi_ulong sc_fp_trigger_sum;
5381 abi_ulong sc_fp_trigger_inst;
5382};
5383
5384struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005385 abi_ulong tuc_flags;
5386 abi_ulong tuc_link;
5387 abi_ulong tuc_osf_sigmask;
5388 target_stack_t tuc_stack;
5389 struct target_sigcontext tuc_mcontext;
5390 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005391};
5392
5393struct target_sigframe {
5394 struct target_sigcontext sc;
5395 unsigned int retcode[3];
5396};
5397
5398struct target_rt_sigframe {
5399 target_siginfo_t info;
5400 struct target_ucontext uc;
5401 unsigned int retcode[3];
5402};
5403
5404#define INSN_MOV_R30_R16 0x47fe0410
5405#define INSN_LDI_R0 0x201f0000
5406#define INSN_CALLSYS 0x00000083
5407
Andreas Färber05390242012-02-25 03:37:53 +01005408static int setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005409 abi_ulong frame_addr, target_sigset_t *set)
5410{
5411 int i, err = 0;
5412
5413 err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5414 err |= __put_user(set->sig[0], &sc->sc_mask);
5415 err |= __put_user(env->pc, &sc->sc_pc);
5416 err |= __put_user(8, &sc->sc_ps);
5417
5418 for (i = 0; i < 31; ++i) {
5419 err |= __put_user(env->ir[i], &sc->sc_regs[i]);
5420 }
5421 err |= __put_user(0, &sc->sc_regs[31]);
5422
5423 for (i = 0; i < 31; ++i) {
5424 err |= __put_user(env->fir[i], &sc->sc_fpregs[i]);
5425 }
5426 err |= __put_user(0, &sc->sc_fpregs[31]);
5427 err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
5428
5429 err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5430 err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5431 err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */
5432
5433 return err;
5434}
5435
Andreas Färber05390242012-02-25 03:37:53 +01005436static int restore_sigcontext(CPUAlphaState *env,
5437 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005438{
5439 uint64_t fpcr;
5440 int i, err = 0;
5441
5442 err |= __get_user(env->pc, &sc->sc_pc);
5443
5444 for (i = 0; i < 31; ++i) {
5445 err |= __get_user(env->ir[i], &sc->sc_regs[i]);
5446 }
5447 for (i = 0; i < 31; ++i) {
5448 err |= __get_user(env->fir[i], &sc->sc_fpregs[i]);
5449 }
5450
5451 err |= __get_user(fpcr, &sc->sc_fpcr);
5452 cpu_alpha_store_fpcr(env, fpcr);
5453
5454 return err;
5455}
5456
5457static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005458 CPUAlphaState *env,
5459 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005460{
5461 abi_ulong sp = env->ir[IR_SP];
5462
5463 /* This is the X/Open sanctioned signal stack switching. */
5464 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5465 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5466 }
5467 return (sp - framesize) & -32;
5468}
5469
5470static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005471 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005472{
5473 abi_ulong frame_addr, r26;
5474 struct target_sigframe *frame;
5475 int err = 0;
5476
5477 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5478 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5479 goto give_sigsegv;
5480 }
5481
5482 err |= setup_sigcontext(&frame->sc, env, frame_addr, set);
5483
5484 if (ka->sa_restorer) {
5485 r26 = ka->sa_restorer;
5486 } else {
5487 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5488 err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5489 &frame->retcode[1]);
5490 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5491 /* imb() */
5492 r26 = frame_addr;
5493 }
5494
5495 unlock_user_struct(frame, frame_addr, 1);
5496
5497 if (err) {
5498 give_sigsegv:
5499 if (sig == TARGET_SIGSEGV) {
5500 ka->_sa_handler = TARGET_SIG_DFL;
5501 }
5502 force_sig(TARGET_SIGSEGV);
5503 }
5504
5505 env->ir[IR_RA] = r26;
5506 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5507 env->ir[IR_A0] = sig;
5508 env->ir[IR_A1] = 0;
5509 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5510 env->ir[IR_SP] = frame_addr;
5511}
5512
5513static void setup_rt_frame(int sig, struct target_sigaction *ka,
5514 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005515 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005516{
5517 abi_ulong frame_addr, r26;
5518 struct target_rt_sigframe *frame;
5519 int i, err = 0;
5520
5521 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5522 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5523 goto give_sigsegv;
5524 }
5525
5526 err |= copy_siginfo_to_user(&frame->info, info);
5527
Aurelien Jarno60e99242010-03-29 02:12:51 +02005528 err |= __put_user(0, &frame->uc.tuc_flags);
5529 err |= __put_user(0, &frame->uc.tuc_link);
5530 err |= __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005531 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005532 &frame->uc.tuc_stack.ss_sp);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005533 err |= __put_user(sas_ss_flags(env->ir[IR_SP]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005534 &frame->uc.tuc_stack.ss_flags);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005535 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005536 &frame->uc.tuc_stack.ss_size);
5537 err |= setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005538 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005539 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005540 }
5541
5542 if (ka->sa_restorer) {
5543 r26 = ka->sa_restorer;
5544 } else {
5545 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5546 err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5547 &frame->retcode[1]);
5548 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5549 /* imb(); */
5550 r26 = frame_addr;
5551 }
5552
5553 if (err) {
5554 give_sigsegv:
5555 if (sig == TARGET_SIGSEGV) {
5556 ka->_sa_handler = TARGET_SIG_DFL;
5557 }
5558 force_sig(TARGET_SIGSEGV);
5559 }
5560
5561 env->ir[IR_RA] = r26;
5562 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5563 env->ir[IR_A0] = sig;
5564 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5565 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5566 env->ir[IR_SP] = frame_addr;
5567}
5568
Andreas Färber05390242012-02-25 03:37:53 +01005569long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005570{
5571 struct target_sigcontext *sc;
5572 abi_ulong sc_addr = env->ir[IR_A0];
5573 target_sigset_t target_set;
5574 sigset_t set;
5575
5576 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5577 goto badframe;
5578 }
5579
5580 target_sigemptyset(&target_set);
5581 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
5582 goto badframe;
5583 }
5584
5585 target_to_host_sigset_internal(&set, &target_set);
5586 sigprocmask(SIG_SETMASK, &set, NULL);
5587
5588 if (restore_sigcontext(env, sc)) {
5589 goto badframe;
5590 }
5591 unlock_user_struct(sc, sc_addr, 0);
5592 return env->ir[IR_V0];
5593
5594 badframe:
5595 unlock_user_struct(sc, sc_addr, 0);
5596 force_sig(TARGET_SIGSEGV);
5597}
5598
Andreas Färber05390242012-02-25 03:37:53 +01005599long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005600{
5601 abi_ulong frame_addr = env->ir[IR_A0];
5602 struct target_rt_sigframe *frame;
5603 sigset_t set;
5604
5605 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5606 goto badframe;
5607 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005608 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005609 sigprocmask(SIG_SETMASK, &set, NULL);
5610
Aurelien Jarno60e99242010-03-29 02:12:51 +02005611 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005612 goto badframe;
5613 }
5614 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005615 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005616 0, env->ir[IR_SP]) == -EFAULT) {
5617 goto badframe;
5618 }
5619
5620 unlock_user_struct(frame, frame_addr, 0);
5621 return env->ir[IR_V0];
5622
5623
5624 badframe:
5625 unlock_user_struct(frame, frame_addr, 0);
5626 force_sig(TARGET_SIGSEGV);
5627}
5628
bellardb346ff42003-06-15 20:05:50 +00005629#else
5630
pbrook624f7972008-05-31 16:11:38 +00005631static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005632 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005633{
5634 fprintf(stderr, "setup_frame: not implemented\n");
5635}
5636
pbrook624f7972008-05-31 16:11:38 +00005637static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005638 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005639 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005640{
5641 fprintf(stderr, "setup_rt_frame: not implemented\n");
5642}
5643
Andreas Färber9349b4f2012-03-14 01:38:32 +01005644long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005645{
5646 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005647 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005648}
5649
Andreas Färber9349b4f2012-03-14 01:38:32 +01005650long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005651{
5652 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005653 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005654}
5655
bellard66fb9762003-03-23 01:06:05 +00005656#endif
5657
Andreas Färber9349b4f2012-03-14 01:38:32 +01005658void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005659{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005660 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005661 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005662 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005663 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005664 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005665 struct emulated_sigtable *k;
5666 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005667 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00005668 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00005669
pbrook624f7972008-05-31 16:11:38 +00005670 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005671 return;
5672
pbrook624f7972008-05-31 16:11:38 +00005673 /* FIXME: This is not threadsafe. */
5674 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005675 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5676 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005677 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005678 k++;
bellard31e31b82003-02-18 22:55:36 +00005679 }
5680 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005681 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005682 return;
bellard66fb9762003-03-23 01:06:05 +00005683
bellard31e31b82003-02-18 22:55:36 +00005684 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005685#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005686 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005687#endif
5688 /* dequeue signal */
5689 q = k->first;
5690 k->first = q->next;
5691 if (!k->first)
5692 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005693
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005694 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005695 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005696 sa = NULL;
5697 handler = TARGET_SIG_IGN;
5698 } else {
5699 sa = &sigact_table[sig - 1];
5700 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005701 }
bellard66fb9762003-03-23 01:06:05 +00005702
bellard66fb9762003-03-23 01:06:05 +00005703 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005704 /* default handler : ignore some signal. The other are job control or fatal */
5705 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5706 kill(getpid(),SIGSTOP);
5707 } else if (sig != TARGET_SIGCHLD &&
5708 sig != TARGET_SIGURG &&
5709 sig != TARGET_SIGWINCH &&
5710 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005711 force_sig(sig);
5712 }
5713 } else if (handler == TARGET_SIG_IGN) {
5714 /* ignore sig */
5715 } else if (handler == TARGET_SIG_ERR) {
5716 force_sig(sig);
5717 } else {
bellard9de5e442003-03-23 16:49:39 +00005718 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005719 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005720 /* SA_NODEFER indicates that the current signal should not be
5721 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005722 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005723 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005724
bellard9de5e442003-03-23 16:49:39 +00005725 /* block signals in the handler using Linux */
5726 sigprocmask(SIG_BLOCK, &set, &old_set);
5727 /* save the previous blocked signal state to restore it at the
5728 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005729 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005730
bellardbc8a22c2003-03-30 21:02:40 +00005731 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005732#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005733 {
5734 CPUX86State *env = cpu_env;
5735 if (env->eflags & VM_MASK)
5736 save_v86_state(env);
5737 }
5738#endif
bellard9de5e442003-03-23 16:49:39 +00005739 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005740#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5741 /* These targets do not have traditional signals. */
5742 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5743#else
pbrook624f7972008-05-31 16:11:38 +00005744 if (sa->sa_flags & TARGET_SA_SIGINFO)
5745 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005746 else
pbrook624f7972008-05-31 16:11:38 +00005747 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005748#endif
pbrook624f7972008-05-31 16:11:38 +00005749 if (sa->sa_flags & TARGET_SA_RESETHAND)
5750 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005751 }
bellard66fb9762003-03-23 01:06:05 +00005752 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005753 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005754}