blob: c8a1da0749451f8c9a45ca1425686cc85af9b332 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
19#include <stdlib.h>
20#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000021#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000022#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000023#include <unistd.h>
bellard66fb9762003-03-23 01:06:05 +000024#include <errno.h>
aurel32603e4fd2009-04-15 16:18:38 +000025#include <assert.h>
bellard31e31b82003-02-18 22:55:36 +000026#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030027#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000028
bellard3ef693a2003-03-23 20:17:16 +000029#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000030#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000031#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000032
33//#define DEBUG_SIGNAL
34
blueswir1249c4c32008-10-05 11:09:37 +000035static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000036 .ss_sp = 0,
37 .ss_size = 0,
38 .ss_flags = TARGET_SS_DISABLE,
39};
40
pbrook624f7972008-05-31 16:11:38 +000041static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000042
ths5fafdf22007-09-16 21:08:06 +000043static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000044 void *puc);
45
Arnaud Patard3ca05582009-03-30 01:18:20 +020046static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGHUP] = TARGET_SIGHUP,
48 [SIGINT] = TARGET_SIGINT,
49 [SIGQUIT] = TARGET_SIGQUIT,
50 [SIGILL] = TARGET_SIGILL,
51 [SIGTRAP] = TARGET_SIGTRAP,
52 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000053/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000054 [SIGBUS] = TARGET_SIGBUS,
55 [SIGFPE] = TARGET_SIGFPE,
56 [SIGKILL] = TARGET_SIGKILL,
57 [SIGUSR1] = TARGET_SIGUSR1,
58 [SIGSEGV] = TARGET_SIGSEGV,
59 [SIGUSR2] = TARGET_SIGUSR2,
60 [SIGPIPE] = TARGET_SIGPIPE,
61 [SIGALRM] = TARGET_SIGALRM,
62 [SIGTERM] = TARGET_SIGTERM,
63#ifdef SIGSTKFLT
64 [SIGSTKFLT] = TARGET_SIGSTKFLT,
65#endif
66 [SIGCHLD] = TARGET_SIGCHLD,
67 [SIGCONT] = TARGET_SIGCONT,
68 [SIGSTOP] = TARGET_SIGSTOP,
69 [SIGTSTP] = TARGET_SIGTSTP,
70 [SIGTTIN] = TARGET_SIGTTIN,
71 [SIGTTOU] = TARGET_SIGTTOU,
72 [SIGURG] = TARGET_SIGURG,
73 [SIGXCPU] = TARGET_SIGXCPU,
74 [SIGXFSZ] = TARGET_SIGXFSZ,
75 [SIGVTALRM] = TARGET_SIGVTALRM,
76 [SIGPROF] = TARGET_SIGPROF,
77 [SIGWINCH] = TARGET_SIGWINCH,
78 [SIGIO] = TARGET_SIGIO,
79 [SIGPWR] = TARGET_SIGPWR,
80 [SIGSYS] = TARGET_SIGSYS,
81 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000082 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080083 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000084 To fix this properly we need to do manual signal delivery multiplexed
85 over a single host signal. */
86 [__SIGRTMIN] = __SIGRTMAX,
87 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000088};
Arnaud Patard3ca05582009-03-30 01:18:20 +020089static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000090
thsa04e1342007-09-27 13:57:58 +000091static inline int on_sig_stack(unsigned long sp)
92{
93 return (sp - target_sigaltstack_used.ss_sp
94 < target_sigaltstack_used.ss_size);
95}
96
97static inline int sas_ss_flags(unsigned long sp)
98{
99 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
100 : on_sig_stack(sp) ? SS_ONSTACK : 0);
101}
102
pbrook1d9d8b52009-04-16 15:17:02 +0000103int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000104{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100105 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000106 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000107 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
pbrook4cb05962008-05-30 18:05:19 +0000110int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000111{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100112 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000113 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000114 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000115}
116
Anthony Liguoric227f092009-10-01 16:12:16 -0500117static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000118{
119 memset(set, 0, sizeof(*set));
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000123{
124 signum--;
125 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
126 set->sig[signum / TARGET_NSIG_BPW] |= mask;
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000130{
131 signum--;
132 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
133 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
134}
135
Anthony Liguoric227f092009-10-01 16:12:16 -0500136static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000137 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000138{
139 int i;
pbrookf5545b52008-05-30 22:37:07 +0000140 target_sigemptyset(d);
141 for (i = 1; i <= TARGET_NSIG; i++) {
142 if (sigismember(s, i)) {
143 target_sigaddset(d, host_to_target_signal(i));
144 }
bellard9e5f5282003-07-13 17:33:54 +0000145 }
bellard66fb9762003-03-23 01:06:05 +0000146}
147
Anthony Liguoric227f092009-10-01 16:12:16 -0500148void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000149{
Anthony Liguoric227f092009-10-01 16:12:16 -0500150 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000151 int i;
152
153 host_to_target_sigset_internal(&d1, s);
154 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200155 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000156}
157
blueswir18fcd3692008-08-17 20:26:25 +0000158static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500159 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000160{
161 int i;
pbrookf5545b52008-05-30 22:37:07 +0000162 sigemptyset(d);
163 for (i = 1; i <= TARGET_NSIG; i++) {
164 if (target_sigismember(s, i)) {
165 sigaddset(d, target_to_host_signal(i));
166 }
167 }
bellard66fb9762003-03-23 01:06:05 +0000168}
169
Anthony Liguoric227f092009-10-01 16:12:16 -0500170void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000171{
Anthony Liguoric227f092009-10-01 16:12:16 -0500172 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000173 int i;
174
175 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200176 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000177 target_to_host_sigset_internal(d, &s1);
178}
ths3b46e622007-09-17 08:09:54 +0000179
blueswir1992f48a2007-10-14 16:27:31 +0000180void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000181 const sigset_t *sigset)
182{
Anthony Liguoric227f092009-10-01 16:12:16 -0500183 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000184 host_to_target_sigset(&d, sigset);
185 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000186}
187
ths5fafdf22007-09-16 21:08:06 +0000188void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000189 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000190{
Anthony Liguoric227f092009-10-01 16:12:16 -0500191 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000192 int i;
193
194 d.sig[0] = *old_sigset;
195 for(i = 1;i < TARGET_NSIG_WORDS; i++)
196 d.sig[i] = 0;
197 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000198}
199
bellard9de5e442003-03-23 16:49:39 +0000200/* siginfo conversion */
201
Anthony Liguoric227f092009-10-01 16:12:16 -0500202static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000203 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000204{
Richard Hendersona05c6402012-09-15 11:34:20 -0700205 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000206 tinfo->si_signo = sig;
207 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000208 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700209
210 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
211 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
212 /* Should never come here, but who knows. The information for
213 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000214 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700215 } else if (sig == TARGET_SIGIO) {
216 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000217 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700218 } else if (sig == TARGET_SIGCHLD) {
219 tinfo->_sifields._sigchld._pid = info->si_pid;
220 tinfo->_sifields._sigchld._uid = info->si_uid;
221 tinfo->_sifields._sigchld._status
222 = host_to_target_waitstatus(info->si_status);
223 tinfo->_sifields._sigchld._utime = info->si_utime;
224 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000225 } else if (sig >= TARGET_SIGRTMIN) {
226 tinfo->_sifields._rt._pid = info->si_pid;
227 tinfo->_sifields._rt._uid = info->si_uid;
228 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700229 tinfo->_sifields._rt._sigval.sival_ptr
230 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000231 }
bellard66fb9762003-03-23 01:06:05 +0000232}
233
Anthony Liguoric227f092009-10-01 16:12:16 -0500234static void tswap_siginfo(target_siginfo_t *tinfo,
235 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000236{
Richard Hendersona05c6402012-09-15 11:34:20 -0700237 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000238 tinfo->si_signo = tswap32(sig);
239 tinfo->si_errno = tswap32(info->si_errno);
240 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700241
242 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
243 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
244 tinfo->_sifields._sigfault._addr
245 = tswapal(info->_sifields._sigfault._addr);
246 } else if (sig == TARGET_SIGIO) {
247 tinfo->_sifields._sigpoll._band
248 = tswap32(info->_sifields._sigpoll._band);
249 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
250 } else if (sig == TARGET_SIGCHLD) {
251 tinfo->_sifields._sigchld._pid
252 = tswap32(info->_sifields._sigchld._pid);
253 tinfo->_sifields._sigchld._uid
254 = tswap32(info->_sifields._sigchld._uid);
255 tinfo->_sifields._sigchld._status
256 = tswap32(info->_sifields._sigchld._status);
257 tinfo->_sifields._sigchld._utime
258 = tswapal(info->_sifields._sigchld._utime);
259 tinfo->_sifields._sigchld._stime
260 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000261 } else if (sig >= TARGET_SIGRTMIN) {
262 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
263 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700264 tinfo->_sifields._rt._sigval.sival_ptr
265 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000266 }
267}
268
269
Anthony Liguoric227f092009-10-01 16:12:16 -0500270void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000271{
272 host_to_target_siginfo_noswap(tinfo, info);
273 tswap_siginfo(tinfo, tinfo);
274}
275
276/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000277/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500278void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000279{
280 info->si_signo = tswap32(tinfo->si_signo);
281 info->si_errno = tswap32(tinfo->si_errno);
282 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000283 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
284 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000285 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200286 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000287}
288
aurel32ca587a82008-12-18 22:44:13 +0000289static int fatal_signal (int sig)
290{
291 switch (sig) {
292 case TARGET_SIGCHLD:
293 case TARGET_SIGURG:
294 case TARGET_SIGWINCH:
295 /* Ignored by default. */
296 return 0;
297 case TARGET_SIGCONT:
298 case TARGET_SIGSTOP:
299 case TARGET_SIGTSTP:
300 case TARGET_SIGTTIN:
301 case TARGET_SIGTTOU:
302 /* Job control signals. */
303 return 0;
304 default:
305 return 1;
306 }
307}
308
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300309/* returns 1 if given signal should dump core if not handled */
310static int core_dump_signal(int sig)
311{
312 switch (sig) {
313 case TARGET_SIGABRT:
314 case TARGET_SIGFPE:
315 case TARGET_SIGILL:
316 case TARGET_SIGQUIT:
317 case TARGET_SIGSEGV:
318 case TARGET_SIGTRAP:
319 case TARGET_SIGBUS:
320 return (1);
321 default:
322 return (0);
323 }
324}
325
bellard31e31b82003-02-18 22:55:36 +0000326void signal_init(void)
327{
328 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000329 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000330 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000331 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000332
bellard9e5f5282003-07-13 17:33:54 +0000333 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200334 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000335 if (host_to_target_signal_table[i] == 0)
336 host_to_target_signal_table[i] = i;
337 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200338 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000339 j = host_to_target_signal_table[i];
340 target_to_host_signal_table[j] = i;
341 }
ths3b46e622007-09-17 08:09:54 +0000342
bellard9de5e442003-03-23 16:49:39 +0000343 /* set all host signal handlers. ALL signals are blocked during
344 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000345 memset(sigact_table, 0, sizeof(sigact_table));
346
bellard9de5e442003-03-23 16:49:39 +0000347 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000348 act.sa_flags = SA_SIGINFO;
349 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000350 for(i = 1; i <= TARGET_NSIG; i++) {
351 host_sig = target_to_host_signal(i);
352 sigaction(host_sig, NULL, &oact);
353 if (oact.sa_sigaction == (void *)SIG_IGN) {
354 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
355 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
356 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
357 }
358 /* If there's already a handler installed then something has
359 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000360 /* Install some handlers for our own use. We need at least
361 SIGSEGV and SIGBUS, to detect exceptions. We can not just
362 trap all signals because it affects syscall interrupt
363 behavior. But do trap all default-fatal signals. */
364 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000365 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000366 }
bellard31e31b82003-02-18 22:55:36 +0000367}
368
bellard66fb9762003-03-23 01:06:05 +0000369/* signal queue handling */
370
Andreas Färber9349b4f2012-03-14 01:38:32 +0100371static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000372{
pbrook624f7972008-05-31 16:11:38 +0000373 TaskState *ts = env->opaque;
374 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000375 if (!q)
376 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000377 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000378 return q;
379}
380
Andreas Färber9349b4f2012-03-14 01:38:32 +0100381static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000382{
pbrook624f7972008-05-31 16:11:38 +0000383 TaskState *ts = env->opaque;
384 q->next = ts->first_free;
385 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000386}
387
bellard9de5e442003-03-23 16:49:39 +0000388/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200389static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000390{
Andreas Färbera2247f82013-06-09 19:47:04 +0200391 CPUArchState *env = thread_cpu->env_ptr;
392 TaskState *ts = (TaskState *)env->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300393 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000394 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200395 host_sig = target_to_host_signal(target_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200396 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000397
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300398 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200399 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300400 stop_all_tasks();
401 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200402 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300403 }
404 if (core_dumped) {
405 /* we already dumped the core of target process, we don't want
406 * a coredump of qemu itself */
407 struct rlimit nodump;
408 getrlimit(RLIMIT_CORE, &nodump);
409 nodump.rlim_cur=0;
410 setrlimit(RLIMIT_CORE, &nodump);
411 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200412 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300413 }
414
Stefan Weil0c587512011-04-28 17:20:32 +0200415 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000416 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
417 * a negative value. To get the proper exit code we need to
418 * actually die from an uncaught signal. Here the default signal
419 * handler is installed, we send ourself a signal and we wait for
420 * it to arrive. */
421 sigfillset(&act.sa_mask);
422 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000423 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000424 sigaction(host_sig, &act, NULL);
425
426 /* For some reason raise(host_sig) doesn't send the signal when
427 * statically linked on x86-64. */
428 kill(getpid(), host_sig);
429
430 /* Make sure the signal isn't masked (just reuse the mask inside
431 of act) */
432 sigdelset(&act.sa_mask, host_sig);
433 sigsuspend(&act.sa_mask);
434
435 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000436 abort();
bellard66fb9762003-03-23 01:06:05 +0000437}
438
bellard9de5e442003-03-23 16:49:39 +0000439/* queue a signal so that it will be send to the virtual CPU as soon
440 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100441int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000442{
pbrook624f7972008-05-31 16:11:38 +0000443 TaskState *ts = env->opaque;
444 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000445 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000446 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000447 int queue;
bellard66fb9762003-03-23 01:06:05 +0000448
bellard9de5e442003-03-23 16:49:39 +0000449#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000450 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000451 sig);
bellard66fb9762003-03-23 01:06:05 +0000452#endif
pbrook624f7972008-05-31 16:11:38 +0000453 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000454 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000455 handler = sigact_table[sig - 1]._sa_handler;
aurel32ca587a82008-12-18 22:44:13 +0000456 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000457 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
458 kill(getpid(),SIGSTOP);
459 return 0;
460 } else
bellard66fb9762003-03-23 01:06:05 +0000461 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000462 if (sig != TARGET_SIGCHLD &&
463 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000464 sig != TARGET_SIGWINCH &&
465 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000466 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000467 } else {
468 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000469 }
aurel32ca587a82008-12-18 22:44:13 +0000470 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000471 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000472 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000473 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000474 force_sig(sig);
475 } else {
bellard9de5e442003-03-23 16:49:39 +0000476 pq = &k->first;
477 if (sig < TARGET_SIGRTMIN) {
478 /* if non real time signal, we queue exactly one signal */
479 if (!k->pending)
480 q = &k->info;
481 else
482 return 0;
483 } else {
484 if (!k->pending) {
485 /* first signal */
486 q = &k->info;
487 } else {
pbrook624f7972008-05-31 16:11:38 +0000488 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000489 if (!q)
490 return -EAGAIN;
491 while (*pq != NULL)
492 pq = &(*pq)->next;
493 }
494 }
495 *pq = q;
496 q->info = *info;
497 q->next = NULL;
498 k->pending = 1;
499 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000500 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000501 return 1; /* indicates that the signal was queued */
502 }
503}
504
ths5fafdf22007-09-16 21:08:06 +0000505static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000506 void *puc)
507{
Andreas Färbera2247f82013-06-09 19:47:04 +0200508 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000509 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500510 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000511
512 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000513 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000514 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000515 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000516 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000517 return;
518 }
519
520 /* get target signal number */
521 sig = host_to_target_signal(host_signum);
522 if (sig < 1 || sig > TARGET_NSIG)
523 return;
524#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000525 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000526#endif
527 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200528 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000529 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200530 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000531 }
bellard31e31b82003-02-18 22:55:36 +0000532}
533
ths0da46a62007-10-20 20:23:07 +0000534/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000535/* compare linux/kernel/signal.c:do_sigaltstack() */
536abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000537{
538 int ret;
539 struct target_sigaltstack oss;
540
541 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000542 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000543 {
544 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
545 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
546 __put_user(sas_ss_flags(sp), &oss.ss_flags);
547 }
548
bellard579a97f2007-11-11 14:26:47 +0000549 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000550 {
bellard579a97f2007-11-11 14:26:47 +0000551 struct target_sigaltstack *uss;
552 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000553
ths0da46a62007-10-20 20:23:07 +0000554 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000555 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000556 || __get_user(ss.ss_sp, &uss->ss_sp)
557 || __get_user(ss.ss_size, &uss->ss_size)
558 || __get_user(ss.ss_flags, &uss->ss_flags))
559 goto out;
bellard579a97f2007-11-11 14:26:47 +0000560 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000561
ths0da46a62007-10-20 20:23:07 +0000562 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000563 if (on_sig_stack(sp))
564 goto out;
565
ths0da46a62007-10-20 20:23:07 +0000566 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000567 if (ss.ss_flags != TARGET_SS_DISABLE
568 && ss.ss_flags != TARGET_SS_ONSTACK
569 && ss.ss_flags != 0)
570 goto out;
571
572 if (ss.ss_flags == TARGET_SS_DISABLE) {
573 ss.ss_size = 0;
574 ss.ss_sp = 0;
575 } else {
ths0da46a62007-10-20 20:23:07 +0000576 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000577 if (ss.ss_size < MINSIGSTKSZ)
578 goto out;
579 }
580
581 target_sigaltstack_used.ss_sp = ss.ss_sp;
582 target_sigaltstack_used.ss_size = ss.ss_size;
583 }
584
bellard579a97f2007-11-11 14:26:47 +0000585 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000586 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000587 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000588 goto out;
thsa04e1342007-09-27 13:57:58 +0000589 }
590
591 ret = 0;
592out:
593 return ret;
594}
595
ths0da46a62007-10-20 20:23:07 +0000596/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000597int do_sigaction(int sig, const struct target_sigaction *act,
598 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000599{
pbrook624f7972008-05-31 16:11:38 +0000600 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000601 struct sigaction act1;
602 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000603 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000604
ths2a913eb2008-11-27 15:46:25 +0000605 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000606 return -EINVAL;
607 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000608#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000609 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
610 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000611#endif
612 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800613 __put_user(k->_sa_handler, &oact->_sa_handler);
614 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000615#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800616 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000617#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800618 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000619 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000620 }
621 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000622 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800623 __get_user(k->_sa_handler, &act->_sa_handler);
624 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000625#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800626 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000627#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800628 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000629 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000630
631 /* we update the host linux signal state */
632 host_sig = target_to_host_signal(sig);
633 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
634 sigfillset(&act1.sa_mask);
635 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000636 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000637 act1.sa_flags |= SA_RESTART;
638 /* NOTE: it is important to update the host kernel signal
639 ignore state to avoid getting unexpected interrupted
640 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000641 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000642 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000643 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000644 if (fatal_signal (sig))
645 act1.sa_sigaction = host_signal_handler;
646 else
647 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000648 } else {
649 act1.sa_sigaction = host_signal_handler;
650 }
ths0da46a62007-10-20 20:23:07 +0000651 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000652 }
bellard66fb9762003-03-23 01:06:05 +0000653 }
ths0da46a62007-10-20 20:23:07 +0000654 return ret;
bellard66fb9762003-03-23 01:06:05 +0000655}
bellard31e31b82003-02-18 22:55:36 +0000656
Anthony Liguoric227f092009-10-01 16:12:16 -0500657static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
658 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000659{
660 tswap_siginfo(tinfo, info);
661 return 0;
662}
663
thsc3b5bc82007-12-02 06:31:25 +0000664static inline int current_exec_domain_sig(int sig)
665{
666 return /* current->exec_domain && current->exec_domain->signal_invmap
667 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
668}
669
bellard459a4012007-11-11 19:45:10 +0000670#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000671
672/* from the Linux kernel */
673
674struct target_fpreg {
675 uint16_t significand[4];
676 uint16_t exponent;
677};
678
679struct target_fpxreg {
680 uint16_t significand[4];
681 uint16_t exponent;
682 uint16_t padding[3];
683};
684
685struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000686 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000687};
688
689struct target_fpstate {
690 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000691 abi_ulong cw;
692 abi_ulong sw;
693 abi_ulong tag;
694 abi_ulong ipoff;
695 abi_ulong cssel;
696 abi_ulong dataoff;
697 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000698 struct target_fpreg _st[8];
699 uint16_t status;
700 uint16_t magic; /* 0xffff = regular FPU data only */
701
702 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000703 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
704 abi_ulong mxcsr;
705 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000706 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
707 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000708 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000709};
710
711#define X86_FXSR_MAGIC 0x0000
712
713struct target_sigcontext {
714 uint16_t gs, __gsh;
715 uint16_t fs, __fsh;
716 uint16_t es, __esh;
717 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000718 abi_ulong edi;
719 abi_ulong esi;
720 abi_ulong ebp;
721 abi_ulong esp;
722 abi_ulong ebx;
723 abi_ulong edx;
724 abi_ulong ecx;
725 abi_ulong eax;
726 abi_ulong trapno;
727 abi_ulong err;
728 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000729 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000730 abi_ulong eflags;
731 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000732 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000733 abi_ulong fpstate; /* pointer */
734 abi_ulong oldmask;
735 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000736};
737
bellard66fb9762003-03-23 01:06:05 +0000738struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000739 abi_ulong tuc_flags;
740 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500741 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000742 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500743 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000744};
745
746struct sigframe
747{
blueswir1992f48a2007-10-14 16:27:31 +0000748 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000749 int sig;
750 struct target_sigcontext sc;
751 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000752 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000753 char retcode[8];
754};
755
756struct rt_sigframe
757{
blueswir1992f48a2007-10-14 16:27:31 +0000758 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000759 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000760 abi_ulong pinfo;
761 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000762 struct target_siginfo info;
763 struct target_ucontext uc;
764 struct target_fpstate fpstate;
765 char retcode[8];
766};
767
768/*
769 * Set up a signal frame.
770 */
771
bellard66fb9762003-03-23 01:06:05 +0000772/* XXX: save x87 state */
773static int
774setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000775 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000776{
777 int err = 0;
bellard775b58d2007-11-11 16:22:17 +0000778 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000779
bellard579a97f2007-11-11 14:26:47 +0000780 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000781 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
782 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
783 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
784 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000785 err |= __put_user(env->regs[R_EDI], &sc->edi);
786 err |= __put_user(env->regs[R_ESI], &sc->esi);
787 err |= __put_user(env->regs[R_EBP], &sc->ebp);
788 err |= __put_user(env->regs[R_ESP], &sc->esp);
789 err |= __put_user(env->regs[R_EBX], &sc->ebx);
790 err |= __put_user(env->regs[R_EDX], &sc->edx);
791 err |= __put_user(env->regs[R_ECX], &sc->ecx);
792 err |= __put_user(env->regs[R_EAX], &sc->eax);
bellard66099dd2003-05-08 15:34:02 +0000793 err |= __put_user(env->exception_index, &sc->trapno);
794 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000795 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000796 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000797 err |= __put_user(env->eflags, &sc->eflags);
798 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000799 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000800
bellard28be6232007-11-11 22:23:38 +0000801 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000802 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000803 magic = 0xffff;
804 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000805 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000806
bellard66fb9762003-03-23 01:06:05 +0000807 /* non-iBCS2 extensions.. */
808 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000809 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000810 return err;
811}
812
813/*
814 * Determine which stack to use..
815 */
816
bellard579a97f2007-11-11 14:26:47 +0000817static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000818get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000819{
820 unsigned long esp;
821
822 /* Default to using normal stack */
823 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000824 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000825 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000826 if (sas_ss_flags(esp) == 0)
827 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
828 }
bellard66fb9762003-03-23 01:06:05 +0000829
830 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000831 else
bellarda52c7572003-06-21 13:14:12 +0000832 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000833 !(ka->sa_flags & TARGET_SA_RESTORER) &&
834 ka->sa_restorer) {
835 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000836 }
bellard579a97f2007-11-11 14:26:47 +0000837 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000838}
839
bellard579a97f2007-11-11 14:26:47 +0000840/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000841static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500842 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000843{
bellard579a97f2007-11-11 14:26:47 +0000844 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000845 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000846 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000847
bellard579a97f2007-11-11 14:26:47 +0000848 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000849
bellard579a97f2007-11-11 14:26:47 +0000850 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000851 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000852
thsc3b5bc82007-12-02 06:31:25 +0000853 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000854 &frame->sig);
855 if (err)
856 goto give_sigsegv;
857
bellard28be6232007-11-11 22:23:38 +0000858 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
859 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000860 if (err)
861 goto give_sigsegv;
862
bellard92319442004-06-19 16:58:13 +0000863 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
864 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
865 goto give_sigsegv;
866 }
bellard66fb9762003-03-23 01:06:05 +0000867
868 /* Set up to return from userspace. If provided, use a stub
869 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000870 if (ka->sa_flags & TARGET_SA_RESTORER) {
871 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000872 } else {
bellard775b58d2007-11-11 16:22:17 +0000873 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000874 abi_ulong retcode_addr;
875 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
876 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000877 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000878 val16 = 0xb858;
879 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000880 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000881 val16 = 0x80cd;
882 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000883 }
884
885 if (err)
886 goto give_sigsegv;
887
888 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000889 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000890 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000891
892 cpu_x86_load_seg(env, R_DS, __USER_DS);
893 cpu_x86_load_seg(env, R_ES, __USER_DS);
894 cpu_x86_load_seg(env, R_SS, __USER_DS);
895 cpu_x86_load_seg(env, R_CS, __USER_CS);
896 env->eflags &= ~TF_MASK;
897
bellard579a97f2007-11-11 14:26:47 +0000898 unlock_user_struct(frame, frame_addr, 1);
899
bellard66fb9762003-03-23 01:06:05 +0000900 return;
901
902give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000903 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000904 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000905 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000906 force_sig(TARGET_SIGSEGV /* , current */);
907}
908
bellard579a97f2007-11-11 14:26:47 +0000909/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000910static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500911 target_siginfo_t *info,
912 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000913{
bellard28be6232007-11-11 22:23:38 +0000914 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000915 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000916 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000917
bellard579a97f2007-11-11 14:26:47 +0000918 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000919
bellard579a97f2007-11-11 14:26:47 +0000920 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000921 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000922
thsc3b5bc82007-12-02 06:31:25 +0000923 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000924 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000925 addr = frame_addr + offsetof(struct rt_sigframe, info);
926 err |= __put_user(addr, &frame->pinfo);
927 addr = frame_addr + offsetof(struct rt_sigframe, uc);
928 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000929 err |= copy_siginfo_to_user(&frame->info, info);
930 if (err)
931 goto give_sigsegv;
932
933 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000934 err |= __put_user(0, &frame->uc.tuc_flags);
935 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000936 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000937 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000938 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000939 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000940 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000941 &frame->uc.tuc_stack.ss_size);
942 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000943 env, set->sig[0],
944 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000945 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000946 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000947 goto give_sigsegv;
948 }
bellard66fb9762003-03-23 01:06:05 +0000949
950 /* Set up to return from userspace. If provided, use a stub
951 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000952 if (ka->sa_flags & TARGET_SA_RESTORER) {
953 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000954 } else {
bellard775b58d2007-11-11 16:22:17 +0000955 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000956 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
957 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000958 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000959 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000960 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000961 val16 = 0x80cd;
962 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000963 }
964
965 if (err)
966 goto give_sigsegv;
967
968 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000969 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000970 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000971
972 cpu_x86_load_seg(env, R_DS, __USER_DS);
973 cpu_x86_load_seg(env, R_ES, __USER_DS);
974 cpu_x86_load_seg(env, R_SS, __USER_DS);
975 cpu_x86_load_seg(env, R_CS, __USER_CS);
976 env->eflags &= ~TF_MASK;
977
bellard579a97f2007-11-11 14:26:47 +0000978 unlock_user_struct(frame, frame_addr, 1);
979
bellard66fb9762003-03-23 01:06:05 +0000980 return;
981
982give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000983 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000984 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000985 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000986 force_sig(TARGET_SIGSEGV /* , current */);
987}
988
989static int
990restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
991{
992 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000993 abi_ulong fpstate_addr;
994 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000995
bellard28be6232007-11-11 22:23:38 +0000996 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
997 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
998 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
999 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001000
bellard28be6232007-11-11 22:23:38 +00001001 env->regs[R_EDI] = tswapl(sc->edi);
1002 env->regs[R_ESI] = tswapl(sc->esi);
1003 env->regs[R_EBP] = tswapl(sc->ebp);
1004 env->regs[R_ESP] = tswapl(sc->esp);
1005 env->regs[R_EBX] = tswapl(sc->ebx);
1006 env->regs[R_EDX] = tswapl(sc->edx);
1007 env->regs[R_ECX] = tswapl(sc->ecx);
1008 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001009
Mike McCormack9a826d72011-06-01 15:14:37 +09001010 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1011 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001012
bellard28be6232007-11-11 22:23:38 +00001013 tmpflags = tswapl(sc->eflags);
1014 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1015 // regs->orig_eax = -1; /* disable syscall checks */
1016
1017 fpstate_addr = tswapl(sc->fpstate);
1018 if (fpstate_addr != 0) {
1019 if (!access_ok(VERIFY_READ, fpstate_addr,
1020 sizeof(struct target_fpstate)))
1021 goto badframe;
1022 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001023 }
1024
bellard28be6232007-11-11 22:23:38 +00001025 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001026 return err;
bellard66fb9762003-03-23 01:06:05 +00001027badframe:
1028 return 1;
bellard66fb9762003-03-23 01:06:05 +00001029}
1030
1031long do_sigreturn(CPUX86State *env)
1032{
bellard579a97f2007-11-11 14:26:47 +00001033 struct sigframe *frame;
1034 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001035 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001036 sigset_t set;
1037 int eax, i;
1038
bellard447db212003-05-10 15:10:36 +00001039#if defined(DEBUG_SIGNAL)
1040 fprintf(stderr, "do_sigreturn\n");
1041#endif
bellard579a97f2007-11-11 14:26:47 +00001042 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1043 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001044 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +00001045 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
1046 goto badframe;
1047 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1048 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
1049 goto badframe;
1050 }
bellard66fb9762003-03-23 01:06:05 +00001051
bellard92319442004-06-19 16:58:13 +00001052 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +00001053 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001054
bellard66fb9762003-03-23 01:06:05 +00001055 /* restore registers */
1056 if (restore_sigcontext(env, &frame->sc, &eax))
1057 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001058 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001059 return eax;
1060
1061badframe:
bellard579a97f2007-11-11 14:26:47 +00001062 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001063 force_sig(TARGET_SIGSEGV);
1064 return 0;
1065}
1066
1067long do_rt_sigreturn(CPUX86State *env)
1068{
bellard28be6232007-11-11 22:23:38 +00001069 abi_ulong frame_addr;
1070 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001071 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001072 int eax;
1073
bellard28be6232007-11-11 22:23:38 +00001074 frame_addr = env->regs[R_ESP] - 4;
1075 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1076 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001077 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +00001078 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001079
bellardb8076a72005-04-07 22:20:31 +00001080 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001081 goto badframe;
1082
bellard28be6232007-11-11 22:23:38 +00001083 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1084 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001085 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001086
bellard28be6232007-11-11 22:23:38 +00001087 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001088 return eax;
1089
1090badframe:
bellard28be6232007-11-11 22:23:38 +00001091 unlock_user_struct(frame, frame_addr, 0);
1092 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001093 return 0;
1094}
1095
Andreas Schwab1744aea2013-09-03 20:12:16 +01001096#elif defined(TARGET_AARCH64)
1097
1098struct target_sigcontext {
1099 uint64_t fault_address;
1100 /* AArch64 registers */
1101 uint64_t regs[31];
1102 uint64_t sp;
1103 uint64_t pc;
1104 uint64_t pstate;
1105 /* 4K reserved for FP/SIMD state and future expansion */
1106 char __reserved[4096] __attribute__((__aligned__(16)));
1107};
1108
1109struct target_ucontext {
1110 abi_ulong tuc_flags;
1111 abi_ulong tuc_link;
1112 target_stack_t tuc_stack;
1113 target_sigset_t tuc_sigmask;
1114 /* glibc uses a 1024-bit sigset_t */
1115 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1116 /* last for future expansion */
1117 struct target_sigcontext tuc_mcontext;
1118};
1119
1120/*
1121 * Header to be used at the beginning of structures extending the user
1122 * context. Such structures must be placed after the rt_sigframe on the stack
1123 * and be 16-byte aligned. The last structure must be a dummy one with the
1124 * magic and size set to 0.
1125 */
1126struct target_aarch64_ctx {
1127 uint32_t magic;
1128 uint32_t size;
1129};
1130
1131#define TARGET_FPSIMD_MAGIC 0x46508001
1132
1133struct target_fpsimd_context {
1134 struct target_aarch64_ctx head;
1135 uint32_t fpsr;
1136 uint32_t fpcr;
1137 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1138};
1139
1140/*
1141 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1142 * user space as it will change with the addition of new context. User space
1143 * should check the magic/size information.
1144 */
1145struct target_aux_context {
1146 struct target_fpsimd_context fpsimd;
1147 /* additional context to be added before "end" */
1148 struct target_aarch64_ctx end;
1149};
1150
1151struct target_rt_sigframe {
1152 struct target_siginfo info;
1153 struct target_ucontext uc;
1154 uint64_t fp;
1155 uint64_t lr;
1156 uint32_t tramp[2];
1157};
1158
1159static int target_setup_sigframe(struct target_rt_sigframe *sf,
1160 CPUARMState *env, target_sigset_t *set)
1161{
1162 int i;
1163 struct target_aux_context *aux =
1164 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1165
1166 /* set up the stack frame for unwinding */
1167 __put_user(env->xregs[29], &sf->fp);
1168 __put_user(env->xregs[30], &sf->lr);
1169
1170 for (i = 0; i < 31; i++) {
1171 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1172 }
1173 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1174 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001175 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001176
1177 __put_user(/*current->thread.fault_address*/ 0,
1178 &sf->uc.tuc_mcontext.fault_address);
1179
1180 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1181 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1182 }
1183
1184 for (i = 0; i < 32; i++) {
1185#ifdef TARGET_WORDS_BIGENDIAN
1186 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1187 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1188#else
1189 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1190 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1191#endif
1192 }
Will Newtone0ee1382014-01-04 22:15:48 +00001193 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1194 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001195 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1196 __put_user(sizeof(struct target_fpsimd_context),
1197 &aux->fpsimd.head.size);
1198
1199 /* set the "end" magic */
1200 __put_user(0, &aux->end.magic);
1201 __put_user(0, &aux->end.size);
1202
1203 return 0;
1204}
1205
1206static int target_restore_sigframe(CPUARMState *env,
1207 struct target_rt_sigframe *sf)
1208{
1209 sigset_t set;
1210 int i;
1211 struct target_aux_context *aux =
1212 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001213 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001214 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001215
1216 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
1217 sigprocmask(SIG_SETMASK, &set, NULL);
1218
1219 for (i = 0; i < 31; i++) {
1220 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1221 }
1222
1223 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1224 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001225 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1226 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001227
1228 __get_user(magic, &aux->fpsimd.head.magic);
1229 __get_user(size, &aux->fpsimd.head.size);
1230
1231 if (magic != TARGET_FPSIMD_MAGIC
1232 || size != sizeof(struct target_fpsimd_context)) {
1233 return 1;
1234 }
1235
Peter Maydell4cf23482014-03-02 19:36:38 +00001236 for (i = 0; i < 32; i++) {
1237#ifdef TARGET_WORDS_BIGENDIAN
1238 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1239 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1240#else
1241 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1242 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1243#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001244 }
Will Newtone0ee1382014-01-04 22:15:48 +00001245 __get_user(fpsr, &aux->fpsimd.fpsr);
1246 vfp_set_fpsr(env, fpsr);
1247 __get_user(fpcr, &aux->fpsimd.fpcr);
1248 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001249
1250 return 0;
1251}
1252
1253static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1254{
1255 abi_ulong sp;
1256
1257 sp = env->xregs[31];
1258
1259 /*
1260 * This is the X/Open sanctioned signal stack switching.
1261 */
1262 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1263 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1264 }
1265
1266 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1267
1268 return sp;
1269}
1270
1271static void target_setup_frame(int usig, struct target_sigaction *ka,
1272 target_siginfo_t *info, target_sigset_t *set,
1273 CPUARMState *env)
1274{
1275 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001276 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001277
1278 frame_addr = get_sigframe(ka, env);
1279 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1280 goto give_sigsegv;
1281 }
1282
1283 __put_user(0, &frame->uc.tuc_flags);
1284 __put_user(0, &frame->uc.tuc_link);
1285
1286 __put_user(target_sigaltstack_used.ss_sp,
1287 &frame->uc.tuc_stack.ss_sp);
1288 __put_user(sas_ss_flags(env->xregs[31]),
1289 &frame->uc.tuc_stack.ss_flags);
1290 __put_user(target_sigaltstack_used.ss_size,
1291 &frame->uc.tuc_stack.ss_size);
1292 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001293 if (ka->sa_flags & TARGET_SA_RESTORER) {
1294 return_addr = ka->sa_restorer;
1295 } else {
1296 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1297 __put_user(0xd2801168, &frame->tramp[0]);
1298 __put_user(0xd4000001, &frame->tramp[1]);
1299 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1300 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001301 env->xregs[0] = usig;
1302 env->xregs[31] = frame_addr;
1303 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1304 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001305 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001306 if (info) {
1307 if (copy_siginfo_to_user(&frame->info, info)) {
1308 goto give_sigsegv;
1309 }
1310 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1311 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1312 }
1313
1314 unlock_user_struct(frame, frame_addr, 1);
1315 return;
1316
1317 give_sigsegv:
1318 unlock_user_struct(frame, frame_addr, 1);
1319 force_sig(TARGET_SIGSEGV);
1320}
1321
1322static void setup_rt_frame(int sig, struct target_sigaction *ka,
1323 target_siginfo_t *info, target_sigset_t *set,
1324 CPUARMState *env)
1325{
1326 target_setup_frame(sig, ka, info, set, env);
1327}
1328
1329static void setup_frame(int sig, struct target_sigaction *ka,
1330 target_sigset_t *set, CPUARMState *env)
1331{
1332 target_setup_frame(sig, ka, 0, set, env);
1333}
1334
1335long do_rt_sigreturn(CPUARMState *env)
1336{
1337 struct target_rt_sigframe *frame;
1338 abi_ulong frame_addr = env->xregs[31];
1339
1340 if (frame_addr & 15) {
1341 goto badframe;
1342 }
1343
1344 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1345 goto badframe;
1346 }
1347
1348 if (target_restore_sigframe(env, frame)) {
1349 goto badframe;
1350 }
1351
1352 if (do_sigaltstack(frame_addr +
1353 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1354 0, get_sp_from_cpustate(env)) == -EFAULT) {
1355 goto badframe;
1356 }
1357
1358 unlock_user_struct(frame, frame_addr, 0);
1359 return env->xregs[0];
1360
1361 badframe:
1362 unlock_user_struct(frame, frame_addr, 0);
1363 force_sig(TARGET_SIGSEGV);
1364 return 0;
1365}
1366
1367long do_sigreturn(CPUARMState *env)
1368{
1369 return do_rt_sigreturn(env);
1370}
1371
bellard43fff232003-07-09 19:31:39 +00001372#elif defined(TARGET_ARM)
1373
1374struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001375 abi_ulong trap_no;
1376 abi_ulong error_code;
1377 abi_ulong oldmask;
1378 abi_ulong arm_r0;
1379 abi_ulong arm_r1;
1380 abi_ulong arm_r2;
1381 abi_ulong arm_r3;
1382 abi_ulong arm_r4;
1383 abi_ulong arm_r5;
1384 abi_ulong arm_r6;
1385 abi_ulong arm_r7;
1386 abi_ulong arm_r8;
1387 abi_ulong arm_r9;
1388 abi_ulong arm_r10;
1389 abi_ulong arm_fp;
1390 abi_ulong arm_ip;
1391 abi_ulong arm_sp;
1392 abi_ulong arm_lr;
1393 abi_ulong arm_pc;
1394 abi_ulong arm_cpsr;
1395 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001396};
1397
pbrooka745ec62008-05-06 15:36:17 +00001398struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001399 abi_ulong tuc_flags;
1400 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001401 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001402 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001403 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001404};
1405
pbrooka745ec62008-05-06 15:36:17 +00001406struct target_ucontext_v2 {
1407 abi_ulong tuc_flags;
1408 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001409 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001410 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001411 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001412 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001413 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1414};
1415
Peter Maydell0d871bd2010-11-24 15:20:05 +00001416struct target_user_vfp {
1417 uint64_t fpregs[32];
1418 abi_ulong fpscr;
1419};
1420
1421struct target_user_vfp_exc {
1422 abi_ulong fpexc;
1423 abi_ulong fpinst;
1424 abi_ulong fpinst2;
1425};
1426
1427struct target_vfp_sigframe {
1428 abi_ulong magic;
1429 abi_ulong size;
1430 struct target_user_vfp ufp;
1431 struct target_user_vfp_exc ufp_exc;
1432} __attribute__((__aligned__(8)));
1433
Peter Maydell08e11252010-11-24 15:20:07 +00001434struct target_iwmmxt_sigframe {
1435 abi_ulong magic;
1436 abi_ulong size;
1437 uint64_t regs[16];
1438 /* Note that not all the coprocessor control registers are stored here */
1439 uint32_t wcssf;
1440 uint32_t wcasf;
1441 uint32_t wcgr0;
1442 uint32_t wcgr1;
1443 uint32_t wcgr2;
1444 uint32_t wcgr3;
1445} __attribute__((__aligned__(8)));
1446
Peter Maydell0d871bd2010-11-24 15:20:05 +00001447#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001448#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001449
pbrooka8c33202008-05-07 23:22:46 +00001450struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001451{
1452 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001453 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1454 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001455};
1456
pbrooka8c33202008-05-07 23:22:46 +00001457struct sigframe_v2
1458{
1459 struct target_ucontext_v2 uc;
1460 abi_ulong retcode;
1461};
1462
pbrooka745ec62008-05-06 15:36:17 +00001463struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001464{
bellardf8b0aa22007-11-11 23:03:42 +00001465 abi_ulong pinfo;
1466 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001467 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001468 struct target_ucontext_v1 uc;
1469 abi_ulong retcode;
1470};
1471
1472struct rt_sigframe_v2
1473{
1474 struct target_siginfo info;
1475 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001476 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001477};
1478
1479#define TARGET_CONFIG_CPU_32 1
1480
1481/*
1482 * For ARM syscalls, we encode the syscall number into the instruction.
1483 */
1484#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1485#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1486
1487/*
1488 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1489 * need two 16-bit instructions.
1490 */
1491#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1492#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1493
blueswir1992f48a2007-10-14 16:27:31 +00001494static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001495 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1496 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1497};
1498
1499
bellard43fff232003-07-09 19:31:39 +00001500#define __get_user_error(x,p,e) __get_user(x, p)
1501
Andreas Färber05390242012-02-25 03:37:53 +01001502static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001503{
1504 return 1;
1505}
1506
pbrooka8c33202008-05-07 23:22:46 +00001507static void
bellard43fff232003-07-09 19:31:39 +00001508setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001509 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001510{
pbrooka8c33202008-05-07 23:22:46 +00001511 __put_user(env->regs[0], &sc->arm_r0);
1512 __put_user(env->regs[1], &sc->arm_r1);
1513 __put_user(env->regs[2], &sc->arm_r2);
1514 __put_user(env->regs[3], &sc->arm_r3);
1515 __put_user(env->regs[4], &sc->arm_r4);
1516 __put_user(env->regs[5], &sc->arm_r5);
1517 __put_user(env->regs[6], &sc->arm_r6);
1518 __put_user(env->regs[7], &sc->arm_r7);
1519 __put_user(env->regs[8], &sc->arm_r8);
1520 __put_user(env->regs[9], &sc->arm_r9);
1521 __put_user(env->regs[10], &sc->arm_r10);
1522 __put_user(env->regs[11], &sc->arm_fp);
1523 __put_user(env->regs[12], &sc->arm_ip);
1524 __put_user(env->regs[13], &sc->arm_sp);
1525 __put_user(env->regs[14], &sc->arm_lr);
1526 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001527#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001528 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001529#endif
1530
pbrooka8c33202008-05-07 23:22:46 +00001531 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1532 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1533 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1534 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001535}
1536
bellard579a97f2007-11-11 14:26:47 +00001537static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001538get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001539{
1540 unsigned long sp = regs->regs[13];
1541
bellard43fff232003-07-09 19:31:39 +00001542 /*
1543 * This is the X/Open sanctioned signal stack switching.
1544 */
pbrook624f7972008-05-31 16:11:38 +00001545 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001546 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001547 /*
1548 * ATPCS B01 mandates 8-byte alignment
1549 */
bellard579a97f2007-11-11 14:26:47 +00001550 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001551}
1552
1553static int
Andreas Färber05390242012-02-25 03:37:53 +01001554setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001555 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001556{
pbrook624f7972008-05-31 16:11:38 +00001557 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001558 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001559 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001560 uint32_t cpsr = cpsr_read(env);
1561
1562 cpsr &= ~CPSR_IT;
1563 if (thumb) {
1564 cpsr |= CPSR_T;
1565 } else {
1566 cpsr &= ~CPSR_T;
1567 }
bellard43fff232003-07-09 19:31:39 +00001568
pbrook624f7972008-05-31 16:11:38 +00001569 if (ka->sa_flags & TARGET_SA_RESTORER) {
1570 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001571 } else {
1572 unsigned int idx = thumb;
1573
pbrook624f7972008-05-31 16:11:38 +00001574 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001575 idx += 2;
1576
1577 if (__put_user(retcodes[idx], rc))
1578 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001579
bellardf8b0aa22007-11-11 23:03:42 +00001580 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001581 }
1582
1583 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001584 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001585 env->regs[14] = retcode;
1586 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001587 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001588
1589 return 0;
1590}
1591
Andreas Färber05390242012-02-25 03:37:53 +01001592static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001593{
1594 int i;
1595 struct target_vfp_sigframe *vfpframe;
1596 vfpframe = (struct target_vfp_sigframe *)regspace;
1597 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1598 __put_user(sizeof(*vfpframe), &vfpframe->size);
1599 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001600 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001601 }
1602 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1603 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1604 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1605 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1606 return (abi_ulong*)(vfpframe+1);
1607}
1608
Andreas Färber05390242012-02-25 03:37:53 +01001609static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1610 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001611{
1612 int i;
1613 struct target_iwmmxt_sigframe *iwmmxtframe;
1614 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1615 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1616 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1617 for (i = 0; i < 16; i++) {
1618 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1619 }
1620 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1621 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1622 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1623 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1624 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1625 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1626 return (abi_ulong*)(iwmmxtframe+1);
1627}
1628
pbrooka8c33202008-05-07 23:22:46 +00001629static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001630 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001631{
pbrooka8c33202008-05-07 23:22:46 +00001632 struct target_sigaltstack stack;
1633 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001634 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001635
1636 /* Clear all the bits of the ucontext we don't use. */
1637 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1638
1639 memset(&stack, 0, sizeof(stack));
1640 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1641 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1642 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1643 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1644
1645 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001646 /* Save coprocessor signal frame. */
1647 regspace = uc->tuc_regspace;
1648 if (arm_feature(env, ARM_FEATURE_VFP)) {
1649 regspace = setup_sigframe_v2_vfp(regspace, env);
1650 }
Peter Maydell08e11252010-11-24 15:20:07 +00001651 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1652 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1653 }
1654
Peter Maydell0d871bd2010-11-24 15:20:05 +00001655 /* Write terminating magic word */
1656 __put_user(0, regspace);
1657
pbrooka8c33202008-05-07 23:22:46 +00001658 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1659 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1660 }
1661}
1662
1663/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001664static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001665 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001666{
1667 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001668 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001669 int i;
bellard43fff232003-07-09 19:31:39 +00001670
bellard579a97f2007-11-11 14:26:47 +00001671 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1672 return;
1673
pbrooka8c33202008-05-07 23:22:46 +00001674 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001675
bellard92319442004-06-19 16:58:13 +00001676 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1677 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001678 goto end;
bellard43fff232003-07-09 19:31:39 +00001679 }
1680
pbrooka8c33202008-05-07 23:22:46 +00001681 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1682 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001683
1684end:
1685 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001686}
1687
pbrook624f7972008-05-31 16:11:38 +00001688static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001689 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001690{
1691 struct sigframe_v2 *frame;
1692 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1693
1694 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1695 return;
1696
1697 setup_sigframe_v2(&frame->uc, set, regs);
1698
1699 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1700 frame_addr + offsetof(struct sigframe_v2, retcode));
1701
1702 unlock_user_struct(frame, frame_addr, 1);
1703}
1704
pbrook624f7972008-05-31 16:11:38 +00001705static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001706 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001707{
1708 if (get_osversion() >= 0x020612) {
1709 setup_frame_v2(usig, ka, set, regs);
1710 } else {
1711 setup_frame_v1(usig, ka, set, regs);
1712 }
bellard43fff232003-07-09 19:31:39 +00001713}
1714
bellard579a97f2007-11-11 14:26:47 +00001715/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001716static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001717 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001718 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001719{
pbrooka745ec62008-05-06 15:36:17 +00001720 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001721 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001722 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001723 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001724 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001725
bellard579a97f2007-11-11 14:26:47 +00001726 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001727 return /* 1 */;
1728
pbrooka745ec62008-05-06 15:36:17 +00001729 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001730 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001731 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001732 __put_user(uc_addr, &frame->puc);
1733 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001734
1735 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001736 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001737
thsa04e1342007-09-27 13:57:58 +00001738 memset(&stack, 0, sizeof(stack));
1739 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1740 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1741 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001742 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001743
pbrooka8c33202008-05-07 23:22:46 +00001744 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001745 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001746 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001747 goto end;
bellard92319442004-06-19 16:58:13 +00001748 }
bellard43fff232003-07-09 19:31:39 +00001749
pbrooka8c33202008-05-07 23:22:46 +00001750 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1751 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001752
pbrooka8c33202008-05-07 23:22:46 +00001753 env->regs[1] = info_addr;
1754 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001755
1756end:
1757 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001758}
1759
pbrook624f7972008-05-31 16:11:38 +00001760static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001761 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001762 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001763{
1764 struct rt_sigframe_v2 *frame;
1765 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001766 abi_ulong info_addr, uc_addr;
1767
1768 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1769 return /* 1 */;
1770
1771 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1772 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001773 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001774
pbrooka8c33202008-05-07 23:22:46 +00001775 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001776
pbrooka8c33202008-05-07 23:22:46 +00001777 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1778 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001779
pbrooka8c33202008-05-07 23:22:46 +00001780 env->regs[1] = info_addr;
1781 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001782
bellard579a97f2007-11-11 14:26:47 +00001783 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001784}
1785
pbrook624f7972008-05-31 16:11:38 +00001786static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001787 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001788 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001789{
1790 if (get_osversion() >= 0x020612) {
1791 setup_rt_frame_v2(usig, ka, info, set, env);
1792 } else {
1793 setup_rt_frame_v1(usig, ka, info, set, env);
1794 }
1795}
1796
bellard43fff232003-07-09 19:31:39 +00001797static int
Andreas Färber05390242012-02-25 03:37:53 +01001798restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001799{
1800 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001801 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001802
1803 __get_user_error(env->regs[0], &sc->arm_r0, err);
1804 __get_user_error(env->regs[1], &sc->arm_r1, err);
1805 __get_user_error(env->regs[2], &sc->arm_r2, err);
1806 __get_user_error(env->regs[3], &sc->arm_r3, err);
1807 __get_user_error(env->regs[4], &sc->arm_r4, err);
1808 __get_user_error(env->regs[5], &sc->arm_r5, err);
1809 __get_user_error(env->regs[6], &sc->arm_r6, err);
1810 __get_user_error(env->regs[7], &sc->arm_r7, err);
1811 __get_user_error(env->regs[8], &sc->arm_r8, err);
1812 __get_user_error(env->regs[9], &sc->arm_r9, err);
1813 __get_user_error(env->regs[10], &sc->arm_r10, err);
1814 __get_user_error(env->regs[11], &sc->arm_fp, err);
1815 __get_user_error(env->regs[12], &sc->arm_ip, err);
1816 __get_user_error(env->regs[13], &sc->arm_sp, err);
1817 __get_user_error(env->regs[14], &sc->arm_lr, err);
1818 __get_user_error(env->regs[15], &sc->arm_pc, err);
1819#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001820 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001821 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001822#endif
1823
1824 err |= !valid_user_regs(env);
1825
1826 return err;
1827}
1828
Andreas Färber05390242012-02-25 03:37:53 +01001829static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001830{
bellardf8b0aa22007-11-11 23:03:42 +00001831 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001832 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001833 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001834 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001835 int i;
bellard43fff232003-07-09 19:31:39 +00001836
1837 /*
1838 * Since we stacked the signal on a 64-bit boundary,
1839 * then 'sp' should be word aligned here. If it's
1840 * not, then the user is trying to mess with us.
1841 */
bellardf8b0aa22007-11-11 23:03:42 +00001842 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001843 if (frame_addr & 7) {
1844 goto badframe;
1845 }
1846
bellardf8b0aa22007-11-11 23:03:42 +00001847 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1848 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001849
bellard92319442004-06-19 16:58:13 +00001850 if (__get_user(set.sig[0], &frame->sc.oldmask))
1851 goto badframe;
1852 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1853 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1854 goto badframe;
1855 }
bellard43fff232003-07-09 19:31:39 +00001856
bellard92319442004-06-19 16:58:13 +00001857 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001858 sigprocmask(SIG_SETMASK, &host_set, NULL);
1859
1860 if (restore_sigcontext(env, &frame->sc))
1861 goto badframe;
1862
1863#if 0
1864 /* Send SIGTRAP if we're single-stepping */
1865 if (ptrace_cancel_bpt(current))
1866 send_sig(SIGTRAP, current, 1);
1867#endif
bellardf8b0aa22007-11-11 23:03:42 +00001868 unlock_user_struct(frame, frame_addr, 0);
1869 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001870
1871badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001872 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001873 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001874 return 0;
1875}
1876
Andreas Färber05390242012-02-25 03:37:53 +01001877static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001878{
1879 int i;
1880 abi_ulong magic, sz;
1881 uint32_t fpscr, fpexc;
1882 struct target_vfp_sigframe *vfpframe;
1883 vfpframe = (struct target_vfp_sigframe *)regspace;
1884
1885 __get_user(magic, &vfpframe->magic);
1886 __get_user(sz, &vfpframe->size);
1887 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1888 return 0;
1889 }
1890 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001891 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001892 }
1893 __get_user(fpscr, &vfpframe->ufp.fpscr);
1894 vfp_set_fpscr(env, fpscr);
1895 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1896 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1897 * and the exception flag is cleared
1898 */
1899 fpexc |= (1 << 30);
1900 fpexc &= ~((1 << 31) | (1 << 28));
1901 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1902 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1903 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1904 return (abi_ulong*)(vfpframe + 1);
1905}
1906
Andreas Färber05390242012-02-25 03:37:53 +01001907static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1908 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001909{
1910 int i;
1911 abi_ulong magic, sz;
1912 struct target_iwmmxt_sigframe *iwmmxtframe;
1913 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1914
1915 __get_user(magic, &iwmmxtframe->magic);
1916 __get_user(sz, &iwmmxtframe->size);
1917 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1918 return 0;
1919 }
1920 for (i = 0; i < 16; i++) {
1921 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1922 }
1923 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1924 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1925 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1926 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1927 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1928 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1929 return (abi_ulong*)(iwmmxtframe + 1);
1930}
1931
Andreas Färber05390242012-02-25 03:37:53 +01001932static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001933 struct target_ucontext_v2 *uc)
1934{
1935 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001936 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001937
1938 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1939 sigprocmask(SIG_SETMASK, &host_set, NULL);
1940
1941 if (restore_sigcontext(env, &uc->tuc_mcontext))
1942 return 1;
1943
Peter Maydell5f9099d2010-11-24 15:20:06 +00001944 /* Restore coprocessor signal frame */
1945 regspace = uc->tuc_regspace;
1946 if (arm_feature(env, ARM_FEATURE_VFP)) {
1947 regspace = restore_sigframe_v2_vfp(env, regspace);
1948 if (!regspace) {
1949 return 1;
1950 }
1951 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001952 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1953 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1954 if (!regspace) {
1955 return 1;
1956 }
1957 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001958
pbrooka8c33202008-05-07 23:22:46 +00001959 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1960 return 1;
1961
1962#if 0
1963 /* Send SIGTRAP if we're single-stepping */
1964 if (ptrace_cancel_bpt(current))
1965 send_sig(SIGTRAP, current, 1);
1966#endif
1967
1968 return 0;
1969}
1970
Andreas Färber05390242012-02-25 03:37:53 +01001971static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001972{
1973 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001974 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00001975
1976 /*
1977 * Since we stacked the signal on a 64-bit boundary,
1978 * then 'sp' should be word aligned here. If it's
1979 * not, then the user is trying to mess with us.
1980 */
pbrooka8c33202008-05-07 23:22:46 +00001981 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001982 if (frame_addr & 7) {
1983 goto badframe;
1984 }
1985
pbrooka8c33202008-05-07 23:22:46 +00001986 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1987 goto badframe;
1988
1989 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1990 goto badframe;
1991
1992 unlock_user_struct(frame, frame_addr, 0);
1993 return env->regs[0];
1994
1995badframe:
1996 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001997 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00001998 return 0;
1999}
2000
Andreas Färber05390242012-02-25 03:37:53 +01002001long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002002{
2003 if (get_osversion() >= 0x020612) {
2004 return do_sigreturn_v2(env);
2005 } else {
2006 return do_sigreturn_v1(env);
2007 }
2008}
2009
Andreas Färber05390242012-02-25 03:37:53 +01002010static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002011{
bellardf8b0aa22007-11-11 23:03:42 +00002012 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002013 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002014 sigset_t host_set;
2015
2016 /*
2017 * Since we stacked the signal on a 64-bit boundary,
2018 * then 'sp' should be word aligned here. If it's
2019 * not, then the user is trying to mess with us.
2020 */
bellardf8b0aa22007-11-11 23:03:42 +00002021 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002022 if (frame_addr & 7) {
2023 goto badframe;
2024 }
2025
bellardf8b0aa22007-11-11 23:03:42 +00002026 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2027 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002028
bellardb8076a72005-04-07 22:20:31 +00002029 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00002030 sigprocmask(SIG_SETMASK, &host_set, NULL);
2031
bellardb8076a72005-04-07 22:20:31 +00002032 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002033 goto badframe;
2034
pbrooka745ec62008-05-06 15:36:17 +00002035 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 +00002036 goto badframe;
2037
bellard43fff232003-07-09 19:31:39 +00002038#if 0
2039 /* Send SIGTRAP if we're single-stepping */
2040 if (ptrace_cancel_bpt(current))
2041 send_sig(SIGTRAP, current, 1);
2042#endif
bellardf8b0aa22007-11-11 23:03:42 +00002043 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002044 return env->regs[0];
2045
2046badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002047 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002048 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002049 return 0;
2050}
2051
Andreas Färber05390242012-02-25 03:37:53 +01002052static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002053{
2054 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002055 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002056
2057 /*
2058 * Since we stacked the signal on a 64-bit boundary,
2059 * then 'sp' should be word aligned here. If it's
2060 * not, then the user is trying to mess with us.
2061 */
pbrooka745ec62008-05-06 15:36:17 +00002062 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002063 if (frame_addr & 7) {
2064 goto badframe;
2065 }
2066
pbrooka745ec62008-05-06 15:36:17 +00002067 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2068 goto badframe;
2069
pbrooka8c33202008-05-07 23:22:46 +00002070 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2071 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002072
pbrooka745ec62008-05-06 15:36:17 +00002073 unlock_user_struct(frame, frame_addr, 0);
2074 return env->regs[0];
2075
2076badframe:
2077 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002078 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002079 return 0;
2080}
2081
Andreas Färber05390242012-02-25 03:37:53 +01002082long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002083{
2084 if (get_osversion() >= 0x020612) {
2085 return do_rt_sigreturn_v2(env);
2086 } else {
2087 return do_rt_sigreturn_v1(env);
2088 }
2089}
2090
bellard6d5e2162004-09-30 22:04:13 +00002091#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002092
bellard6d5e2162004-09-30 22:04:13 +00002093#define __SUNOS_MAXWIN 31
2094
2095/* This is what SunOS does, so shall I. */
2096struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002097 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002098
blueswir1992f48a2007-10-14 16:27:31 +00002099 abi_ulong sigc_mask; /* sigmask to restore */
2100 abi_ulong sigc_sp; /* stack pointer */
2101 abi_ulong sigc_pc; /* program counter */
2102 abi_ulong sigc_npc; /* next program counter */
2103 abi_ulong sigc_psr; /* for condition codes etc */
2104 abi_ulong sigc_g1; /* User uses these two registers */
2105 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002106
2107 /* Now comes information regarding the users window set
2108 * at the time of the signal.
2109 */
blueswir1992f48a2007-10-14 16:27:31 +00002110 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002111
2112 /* stack ptrs for each regwin buf */
2113 char *sigc_spbuf[__SUNOS_MAXWIN];
2114
2115 /* Windows to restore after signal */
2116 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002117 abi_ulong locals[8];
2118 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002119 } sigc_wbuf[__SUNOS_MAXWIN];
2120};
2121/* A Sparc stack frame */
2122struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002123 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002124 abi_ulong ins[8];
2125 /* It's simpler to treat fp and callers_pc as elements of ins[]
2126 * since we never need to access them ourselves.
2127 */
bellard6d5e2162004-09-30 22:04:13 +00002128 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002129 abi_ulong xargs[6];
2130 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002131};
2132
2133typedef struct {
2134 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002135 abi_ulong psr;
2136 abi_ulong pc;
2137 abi_ulong npc;
2138 abi_ulong y;
2139 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002140 } si_regs;
2141 int si_mask;
2142} __siginfo_t;
2143
2144typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002145 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002146 unsigned long si_fsr;
2147 unsigned long si_fpqdepth;
2148 struct {
2149 unsigned long *insn_addr;
2150 unsigned long insn;
2151 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002152} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002153
2154
2155struct target_signal_frame {
2156 struct sparc_stackf ss;
2157 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002158 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002159 abi_ulong insns[2] __attribute__ ((aligned (8)));
2160 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2161 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002162 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002163};
2164struct target_rt_signal_frame {
2165 struct sparc_stackf ss;
2166 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002167 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002168 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002169 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002170 unsigned int insns[2];
2171 stack_t stack;
2172 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002173 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002174};
2175
bellarde80cfcf2004-12-19 23:18:01 +00002176#define UREG_O0 16
2177#define UREG_O6 22
2178#define UREG_I0 0
2179#define UREG_I1 1
2180#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002181#define UREG_I3 3
2182#define UREG_I4 4
2183#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002184#define UREG_I6 6
2185#define UREG_I7 7
2186#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002187#define UREG_FP UREG_I6
2188#define UREG_SP UREG_O6
2189
pbrook624f7972008-05-31 16:11:38 +00002190static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002191 CPUSPARCState *env,
2192 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002193{
bellard459a4012007-11-11 19:45:10 +00002194 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002195
2196 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002197
2198 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002199 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002200 if (!on_sig_stack(sp)
2201 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2202 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002203 }
bellard459a4012007-11-11 19:45:10 +00002204 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002205}
2206
2207static int
Andreas Färber05390242012-02-25 03:37:53 +01002208setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002209{
2210 int err = 0, i;
2211
bellard6d5e2162004-09-30 22:04:13 +00002212 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00002213 err |= __put_user(env->pc, &si->si_regs.pc);
2214 err |= __put_user(env->npc, &si->si_regs.npc);
2215 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002216 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00002217 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
2218 }
bellarda315a142005-01-30 22:59:18 +00002219 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002220 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002221 }
bellard6d5e2162004-09-30 22:04:13 +00002222 err |= __put_user(mask, &si->si_mask);
2223 return err;
2224}
bellarde80cfcf2004-12-19 23:18:01 +00002225
bellard80a9d032005-01-03 23:31:27 +00002226#if 0
bellard6d5e2162004-09-30 22:04:13 +00002227static int
2228setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002229 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002230{
2231 int err = 0;
2232
2233 err |= __put_user(mask, &sc->sigc_mask);
2234 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2235 err |= __put_user(env->pc, &sc->sigc_pc);
2236 err |= __put_user(env->npc, &sc->sigc_npc);
2237 err |= __put_user(env->psr, &sc->sigc_psr);
2238 err |= __put_user(env->gregs[1], &sc->sigc_g1);
2239 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
2240
2241 return err;
2242}
bellard80a9d032005-01-03 23:31:27 +00002243#endif
bellard6d5e2162004-09-30 22:04:13 +00002244#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2245
pbrook624f7972008-05-31 16:11:38 +00002246static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002247 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002248{
bellard459a4012007-11-11 19:45:10 +00002249 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002250 struct target_signal_frame *sf;
2251 int sigframe_size, err, i;
2252
2253 /* 1. Make sure everything is clean */
2254 //synchronize_user_stack();
2255
2256 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002257 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002258
bellard459a4012007-11-11 19:45:10 +00002259 sf = lock_user(VERIFY_WRITE, sf_addr,
2260 sizeof(struct target_signal_frame), 0);
2261 if (!sf)
2262 goto sigsegv;
2263
bellarde80cfcf2004-12-19 23:18:01 +00002264 //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 +00002265#if 0
2266 if (invalid_frame_pointer(sf, sigframe_size))
2267 goto sigill_and_return;
2268#endif
2269 /* 2. Save the current process state */
2270 err = setup___siginfo(&sf->info, env, set->sig[0]);
2271 err |= __put_user(0, &sf->extra_size);
2272
2273 //err |= save_fpu_state(regs, &sf->fpu_state);
2274 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
2275
2276 err |= __put_user(set->sig[0], &sf->info.si_mask);
2277 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2278 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
2279 }
2280
bellarda315a142005-01-30 22:59:18 +00002281 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002282 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002283 }
bellarda315a142005-01-30 22:59:18 +00002284 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002285 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002286 }
bellard6d5e2162004-09-30 22:04:13 +00002287 if (err)
2288 goto sigsegv;
2289
2290 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002291 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002292 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002293 env->regwptr[UREG_I1] = sf_addr +
2294 offsetof(struct target_signal_frame, info);
2295 env->regwptr[UREG_I2] = sf_addr +
2296 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002297
2298 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002299 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002300 env->npc = (env->pc + 4);
2301 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002302 if (ka->sa_restorer)
2303 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002304 else {
bellard775b58d2007-11-11 16:22:17 +00002305 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002306
2307 env->regwptr[UREG_I7] = sf_addr +
2308 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002309
2310 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002311 val32 = 0x821020d8;
2312 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002313
2314 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002315 val32 = 0x91d02010;
2316 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002317 if (err)
2318 goto sigsegv;
2319
2320 /* Flush instruction space. */
2321 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002322 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002323 }
bellard459a4012007-11-11 19:45:10 +00002324 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002325 return;
bellard459a4012007-11-11 19:45:10 +00002326#if 0
2327sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002328 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002329#endif
bellard6d5e2162004-09-30 22:04:13 +00002330sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002331 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002332 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002333 force_sig(TARGET_SIGSEGV);
2334}
2335static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002336restore_fpu_state(CPUSPARCState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00002337{
2338 int err;
2339#if 0
2340#ifdef CONFIG_SMP
2341 if (current->flags & PF_USEDFPU)
2342 regs->psr &= ~PSR_EF;
2343#else
2344 if (current == last_task_used_math) {
2345 last_task_used_math = 0;
2346 regs->psr &= ~PSR_EF;
2347 }
2348#endif
2349 current->used_math = 1;
2350 current->flags &= ~PF_USEDFPU;
2351#endif
2352#if 0
2353 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
2354 return -EFAULT;
2355#endif
2356
bellardfafffae2006-10-28 12:09:16 +00002357 /* XXX: incorrect */
Blue Swirl8954bae2012-07-30 15:29:11 +00002358 err = copy_from_user(&env->fpr[0], fpu->si_float_regs[0],
2359 (sizeof(abi_ulong) * 32));
bellard6d5e2162004-09-30 22:04:13 +00002360 err |= __get_user(env->fsr, &fpu->si_fsr);
2361#if 0
2362 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
2363 if (current->thread.fpqdepth != 0)
2364 err |= __copy_from_user(&current->thread.fpqueue[0],
2365 &fpu->si_fpqueue[0],
2366 ((sizeof(unsigned long) +
2367 (sizeof(unsigned long *)))*16));
2368#endif
2369 return err;
2370}
2371
2372
pbrook624f7972008-05-31 16:11:38 +00002373static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002374 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002375 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002376{
2377 fprintf(stderr, "setup_rt_frame: not implemented\n");
2378}
2379
Andreas Färber05390242012-02-25 03:37:53 +01002380long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002381{
bellardf8b0aa22007-11-11 23:03:42 +00002382 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002383 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002384 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002385 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002386 sigset_t host_set;
bellarde80cfcf2004-12-19 23:18:01 +00002387 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00002388
bellardf8b0aa22007-11-11 23:03:42 +00002389 sf_addr = env->regwptr[UREG_FP];
2390 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2391 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002392#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002393 fprintf(stderr, "sigreturn\n");
2394 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 +00002395#endif
bellarde80cfcf2004-12-19 23:18:01 +00002396 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002397
2398 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002399
bellardf8b0aa22007-11-11 23:03:42 +00002400 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002401 goto segv_and_exit;
2402
2403 err = __get_user(pc, &sf->info.si_regs.pc);
2404 err |= __get_user(npc, &sf->info.si_regs.npc);
2405
bellard6d5e2162004-09-30 22:04:13 +00002406 if ((pc | npc) & 3)
2407 goto segv_and_exit;
2408
2409 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00002410 err |= __get_user(up_psr, &sf->info.si_regs.psr);
2411
bellard6d5e2162004-09-30 22:04:13 +00002412 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002413 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2414 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2415
2416 env->pc = pc;
2417 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00002418 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002419 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002420 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2421 }
bellarda315a142005-01-30 22:59:18 +00002422 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002423 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2424 }
bellard6d5e2162004-09-30 22:04:13 +00002425
Peter Maydell2aec3a22011-06-16 17:37:14 +01002426 /* FIXME: implement FPU save/restore:
2427 * __get_user(fpu_save, &sf->fpu_save);
2428 * if (fpu_save)
2429 * err |= restore_fpu_state(env, fpu_save);
2430 */
bellard6d5e2162004-09-30 22:04:13 +00002431
2432 /* This is pretty much atomic, no amount locking would prevent
2433 * the races which exist anyways.
2434 */
2435 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002436 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2437 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
2438 }
2439
2440 target_to_host_sigset_internal(&host_set, &set);
2441 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002442
2443 if (err)
2444 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002445 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002446 return env->regwptr[0];
2447
2448segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002449 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002450 force_sig(TARGET_SIGSEGV);
2451}
2452
Andreas Färber05390242012-02-25 03:37:53 +01002453long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002454{
2455 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002456 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002457}
2458
bellard459a4012007-11-11 19:45:10 +00002459#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002460#define MC_TSTATE 0
2461#define MC_PC 1
2462#define MC_NPC 2
2463#define MC_Y 3
2464#define MC_G1 4
2465#define MC_G2 5
2466#define MC_G3 6
2467#define MC_G4 7
2468#define MC_G5 8
2469#define MC_G6 9
2470#define MC_G7 10
2471#define MC_O0 11
2472#define MC_O1 12
2473#define MC_O2 13
2474#define MC_O3 14
2475#define MC_O4 15
2476#define MC_O5 16
2477#define MC_O6 17
2478#define MC_O7 18
2479#define MC_NGREG 19
2480
Anthony Liguoric227f092009-10-01 16:12:16 -05002481typedef abi_ulong target_mc_greg_t;
2482typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002483
2484struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002485 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002486 uint32_t mcfq_insn;
2487};
2488
2489struct target_mc_fpu {
2490 union {
2491 uint32_t sregs[32];
2492 uint64_t dregs[32];
2493 //uint128_t qregs[16];
2494 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002495 abi_ulong mcfpu_fsr;
2496 abi_ulong mcfpu_fprs;
2497 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002498 struct target_mc_fq *mcfpu_fq;
2499 unsigned char mcfpu_qcnt;
2500 unsigned char mcfpu_qentsz;
2501 unsigned char mcfpu_enab;
2502};
Anthony Liguoric227f092009-10-01 16:12:16 -05002503typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002504
2505typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002506 target_mc_gregset_t mc_gregs;
2507 target_mc_greg_t mc_fp;
2508 target_mc_greg_t mc_i7;
2509 target_mc_fpu_t mc_fpregs;
2510} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002511
2512struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002513 struct target_ucontext *tuc_link;
2514 abi_ulong tuc_flags;
2515 target_sigset_t tuc_sigmask;
2516 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002517};
2518
2519/* A V9 register window */
2520struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002521 abi_ulong locals[8];
2522 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002523};
2524
2525#define TARGET_STACK_BIAS 2047
2526
2527/* {set, get}context() needed for 64-bit SparcLinux userland. */
2528void sparc64_set_context(CPUSPARCState *env)
2529{
bellard459a4012007-11-11 19:45:10 +00002530 abi_ulong ucp_addr;
2531 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002532 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002533 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002534 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002535 int err;
2536 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002537
bellard459a4012007-11-11 19:45:10 +00002538 ucp_addr = env->regwptr[UREG_I0];
2539 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2540 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002541 grp = &ucp->tuc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002542 err = __get_user(pc, &((*grp)[MC_PC]));
2543 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002544 if (err || ((pc | npc) & 3))
2545 goto do_sigsegv;
2546 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002547 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002548 sigset_t set;
2549
2550 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002551 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002552 goto do_sigsegv;
2553 } else {
bellard459a4012007-11-11 19:45:10 +00002554 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002555 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002556 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002557 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002558 err |= __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002559 }
blueswir15bfb56b2007-10-05 17:01:51 +00002560 if (err)
2561 goto do_sigsegv;
2562 }
2563 target_to_host_sigset_internal(&set, &target_set);
2564 sigprocmask(SIG_SETMASK, &set, NULL);
2565 }
2566 env->pc = pc;
2567 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002568 err |= __get_user(env->y, &((*grp)[MC_Y]));
2569 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002570 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002571 cpu_put_ccr(env, tstate >> 32);
2572 cpu_put_cwp64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002573 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2574 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2575 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2576 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2577 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2578 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2579 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2580 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2581 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2582 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2583 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2584 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2585 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2586 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2587 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002588
Aurelien Jarno60e99242010-03-29 02:12:51 +02002589 err |= __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2590 err |= __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002591
bellard459a4012007-11-11 19:45:10 +00002592 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2593 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2594 abi_ulong) != 0)
2595 goto do_sigsegv;
2596 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2597 abi_ulong) != 0)
2598 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002599 /* FIXME this does not match how the kernel handles the FPU in
2600 * its sparc64_set_context implementation. In particular the FPU
2601 * is only restored if fenab is non-zero in:
2602 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2603 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002604 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002605 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002606 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2607 for (i = 0; i < 64; i++, src++) {
2608 if (i & 1) {
2609 err |= __get_user(env->fpr[i/2].l.lower, src);
2610 } else {
2611 err |= __get_user(env->fpr[i/2].l.upper, src);
2612 }
2613 }
bellard459a4012007-11-11 19:45:10 +00002614 }
bellard579a97f2007-11-11 14:26:47 +00002615 err |= __get_user(env->fsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002616 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
bellard579a97f2007-11-11 14:26:47 +00002617 err |= __get_user(env->gsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002618 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002619 if (err)
2620 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002621 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002622 return;
2623 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002624 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002625 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002626}
2627
2628void sparc64_get_context(CPUSPARCState *env)
2629{
bellard459a4012007-11-11 19:45:10 +00002630 abi_ulong ucp_addr;
2631 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002632 target_mc_gregset_t *grp;
2633 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002634 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002635 int err;
2636 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002637 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002638 sigset_t set;
2639
bellard459a4012007-11-11 19:45:10 +00002640 ucp_addr = env->regwptr[UREG_I0];
2641 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2642 goto do_sigsegv;
2643
Aurelien Jarno60e99242010-03-29 02:12:51 +02002644 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002645 grp = &mcp->mc_gregs;
2646
2647 /* Skip over the trap instruction, first. */
2648 env->pc = env->npc;
2649 env->npc += 4;
2650
2651 err = 0;
2652
2653 sigprocmask(0, NULL, &set);
2654 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002655 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002656 err |= __put_user(target_set.sig[0],
Aurelien Jarno60e99242010-03-29 02:12:51 +02002657 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002658 } else {
2659 abi_ulong *src, *dst;
2660 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002661 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002662 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002663 err |= __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002664 }
blueswir15bfb56b2007-10-05 17:01:51 +00002665 if (err)
2666 goto do_sigsegv;
2667 }
2668
bellard459a4012007-11-11 19:45:10 +00002669 /* XXX: tstate must be saved properly */
2670 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002671 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2672 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2673 err |= __put_user(env->y, &((*grp)[MC_Y]));
2674 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2675 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2676 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2677 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2678 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2679 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2680 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2681 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2682 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2683 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2684 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2685 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2686 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2687 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2688 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002689
bellard459a4012007-11-11 19:45:10 +00002690 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2691 fp = i7 = 0;
2692 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2693 abi_ulong) != 0)
2694 goto do_sigsegv;
2695 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2696 abi_ulong) != 0)
2697 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002698 err |= __put_user(fp, &(mcp->mc_fp));
2699 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002700
bellard459a4012007-11-11 19:45:10 +00002701 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002702 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2703 for (i = 0; i < 64; i++, dst++) {
2704 if (i & 1) {
2705 err |= __put_user(env->fpr[i/2].l.lower, dst);
2706 } else {
2707 err |= __put_user(env->fpr[i/2].l.upper, dst);
2708 }
2709 }
bellard459a4012007-11-11 19:45:10 +00002710 }
bellard579a97f2007-11-11 14:26:47 +00002711 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2712 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2713 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002714
2715 if (err)
2716 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002717 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002718 return;
2719 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002720 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002721 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002722}
2723#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002724#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002725
Richard Hendersonff970902013-02-10 10:30:42 -08002726# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002727struct target_sigcontext {
2728 uint32_t sc_regmask; /* Unused */
2729 uint32_t sc_status;
2730 uint64_t sc_pc;
2731 uint64_t sc_regs[32];
2732 uint64_t sc_fpregs[32];
2733 uint32_t sc_ownedfp; /* Unused */
2734 uint32_t sc_fpc_csr;
2735 uint32_t sc_fpc_eir; /* Unused */
2736 uint32_t sc_used_math;
2737 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002738 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002739 uint64_t sc_mdhi;
2740 uint64_t sc_mdlo;
2741 target_ulong sc_hi1; /* Was sc_cause */
2742 target_ulong sc_lo1; /* Was sc_badvaddr */
2743 target_ulong sc_hi2; /* Was sc_sigset[4] */
2744 target_ulong sc_lo2;
2745 target_ulong sc_hi3;
2746 target_ulong sc_lo3;
2747};
Richard Hendersonff970902013-02-10 10:30:42 -08002748# else /* N32 || N64 */
2749struct target_sigcontext {
2750 uint64_t sc_regs[32];
2751 uint64_t sc_fpregs[32];
2752 uint64_t sc_mdhi;
2753 uint64_t sc_hi1;
2754 uint64_t sc_hi2;
2755 uint64_t sc_hi3;
2756 uint64_t sc_mdlo;
2757 uint64_t sc_lo1;
2758 uint64_t sc_lo2;
2759 uint64_t sc_lo3;
2760 uint64_t sc_pc;
2761 uint32_t sc_fpc_csr;
2762 uint32_t sc_used_math;
2763 uint32_t sc_dsp;
2764 uint32_t sc_reserved;
2765};
2766# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002767
2768struct sigframe {
2769 uint32_t sf_ass[4]; /* argument save space for o32 */
2770 uint32_t sf_code[2]; /* signal trampoline */
2771 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002772 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002773};
2774
pbrook0b1bcb02009-04-21 01:41:10 +00002775struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002776 target_ulong tuc_flags;
2777 target_ulong tuc_link;
2778 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002779 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002780 struct target_sigcontext tuc_mcontext;
2781 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002782};
2783
2784struct target_rt_sigframe {
2785 uint32_t rs_ass[4]; /* argument save space for o32 */
2786 uint32_t rs_code[2]; /* signal trampoline */
2787 struct target_siginfo rs_info;
2788 struct target_ucontext rs_uc;
2789};
2790
bellard106ec872006-06-27 21:08:10 +00002791/* Install trampoline to jump back from signal handler */
2792static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2793{
Richard Henderson084d0492013-02-10 10:30:44 -08002794 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002795
2796 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002797 * Set up the return code ...
2798 *
2799 * li v0, __NR__foo_sigreturn
2800 * syscall
2801 */
bellard106ec872006-06-27 21:08:10 +00002802
Richard Henderson084d0492013-02-10 10:30:44 -08002803 err |= __put_user(0x24020000 + syscall, tramp + 0);
bellard106ec872006-06-27 21:08:10 +00002804 err |= __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002805 return err;
2806}
2807
2808static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002809setup_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002810{
2811 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002812 int i;
bellard106ec872006-06-27 21:08:10 +00002813
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002814 err |= __put_user(exception_resume_pc(regs), &sc->sc_pc);
2815 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002816
Richard Henderson084d0492013-02-10 10:30:44 -08002817 __put_user(0, &sc->sc_regs[0]);
2818 for (i = 1; i < 32; ++i) {
2819 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
2820 }
bellard106ec872006-06-27 21:08:10 +00002821
thsb5dc7732008-06-27 10:02:35 +00002822 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2823 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002824
Richard Henderson084d0492013-02-10 10:30:44 -08002825 /* Rather than checking for dsp existence, always copy. The storage
2826 would just be garbage otherwise. */
2827 err |= __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2828 err |= __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2829 err |= __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2830 err |= __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2831 err |= __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2832 err |= __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
2833 {
2834 uint32_t dsp = cpu_rddsp(0x3ff, regs);
2835 err |= __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002836 }
Richard Henderson084d0492013-02-10 10:30:44 -08002837
2838 err |= __put_user(1, &sc->sc_used_math);
2839
2840 for (i = 0; i < 32; ++i) {
2841 err |= __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002842 }
bellard106ec872006-06-27 21:08:10 +00002843
bellard106ec872006-06-27 21:08:10 +00002844 return err;
2845}
2846
2847static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002848restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002849{
2850 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002851 int i;
bellard106ec872006-06-27 21:08:10 +00002852
2853 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2854
thsb5dc7732008-06-27 10:02:35 +00002855 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2856 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002857
Richard Henderson084d0492013-02-10 10:30:44 -08002858 for (i = 1; i < 32; ++i) {
2859 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002860 }
2861
Richard Henderson084d0492013-02-10 10:30:44 -08002862 err |= __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2863 err |= __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2864 err |= __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2865 err |= __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2866 err |= __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2867 err |= __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
2868 {
2869 uint32_t dsp;
2870 err |= __get_user(dsp, &sc->sc_dsp);
2871 cpu_wrdsp(dsp, 0x3ff, regs);
2872 }
2873
2874 for (i = 0; i < 32; ++i) {
2875 err |= __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
2876 }
2877
bellard106ec872006-06-27 21:08:10 +00002878 return err;
2879}
Richard Hendersonff970902013-02-10 10:30:42 -08002880
bellard106ec872006-06-27 21:08:10 +00002881/*
2882 * Determine which stack to use..
2883 */
bellard579a97f2007-11-11 14:26:47 +00002884static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002885get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002886{
2887 unsigned long sp;
2888
2889 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002890 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002891
2892 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002893 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002894 * above the user stack, 16-bytes before the next lowest
2895 * 16 byte boundary. Try to avoid trashing it.
2896 */
2897 sp -= 32;
2898
bellard106ec872006-06-27 21:08:10 +00002899 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002900 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002901 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2902 }
bellard106ec872006-06-27 21:08:10 +00002903
bellard579a97f2007-11-11 14:26:47 +00002904 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002905}
2906
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002907static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2908{
2909 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2910 env->hflags &= ~MIPS_HFLAG_M16;
2911 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2912 env->active_tc.PC &= ~(target_ulong) 1;
2913 }
2914}
2915
Richard Hendersonff970902013-02-10 10:30:42 -08002916# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002917/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002918static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002919 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002920{
2921 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002922 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002923 int i;
2924
bellard579a97f2007-11-11 14:26:47 +00002925 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2926 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002927 goto give_sigsegv;
2928
2929 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2930
2931 if(setup_sigcontext(regs, &frame->sf_sc))
2932 goto give_sigsegv;
2933
2934 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2935 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2936 goto give_sigsegv;
2937 }
2938
2939 /*
2940 * Arguments to signal handler:
2941 *
2942 * a0 = signal number
2943 * a1 = 0 (should be cause)
2944 * a2 = pointer to struct sigcontext
2945 *
2946 * $25 and PC point to the signal handler, $29 points to the
2947 * struct sigframe.
2948 */
thsb5dc7732008-06-27 10:02:35 +00002949 regs->active_tc.gpr[ 4] = sig;
2950 regs->active_tc.gpr[ 5] = 0;
2951 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2952 regs->active_tc.gpr[29] = frame_addr;
2953 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002954 /* The original kernel code sets CP0_EPC to the handler
2955 * since it returns to userland using eret
2956 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002957 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002958 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002959 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002960 return;
2961
2962give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002963 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002964 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002965}
2966
Andreas Färber05390242012-02-25 03:37:53 +01002967long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002968{
ths388bb212007-05-13 13:58:00 +00002969 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002970 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002971 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002972 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002973 int i;
bellard106ec872006-06-27 21:08:10 +00002974
2975#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002976 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002977#endif
thsb5dc7732008-06-27 10:02:35 +00002978 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002979 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002980 goto badframe;
2981
ths388bb212007-05-13 13:58:00 +00002982 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002983 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2984 goto badframe;
ths388bb212007-05-13 13:58:00 +00002985 }
bellard106ec872006-06-27 21:08:10 +00002986
ths388bb212007-05-13 13:58:00 +00002987 target_to_host_sigset_internal(&blocked, &target_set);
2988 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002989
ths388bb212007-05-13 13:58:00 +00002990 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002991 goto badframe;
2992
2993#if 0
ths388bb212007-05-13 13:58:00 +00002994 /*
2995 * Don't let your children do this ...
2996 */
2997 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002998 "move\t$29, %0\n\t"
2999 "j\tsyscall_exit"
3000 :/* no outputs */
3001 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003002 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003003#endif
ths3b46e622007-09-17 08:09:54 +00003004
thsb5dc7732008-06-27 10:02:35 +00003005 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003006 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003007 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003008 * maybe a problem with nested signals ? */
3009 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003010 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003011
3012badframe:
ths388bb212007-05-13 13:58:00 +00003013 force_sig(TARGET_SIGSEGV/*, current*/);
3014 return 0;
bellard106ec872006-06-27 21:08:10 +00003015}
Richard Hendersonff970902013-02-10 10:30:42 -08003016# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003017
pbrook624f7972008-05-31 16:11:38 +00003018static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003019 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003020 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003021{
pbrook0b1bcb02009-04-21 01:41:10 +00003022 struct target_rt_sigframe *frame;
3023 abi_ulong frame_addr;
3024 int i;
3025
3026 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3027 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3028 goto give_sigsegv;
3029
3030 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3031
3032 copy_siginfo_to_user(&frame->rs_info, info);
3033
Aurelien Jarno60e99242010-03-29 02:12:51 +02003034 __put_user(0, &frame->rs_uc.tuc_flags);
3035 __put_user(0, &frame->rs_uc.tuc_link);
3036 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3037 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003038 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003039 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003040
Aurelien Jarno60e99242010-03-29 02:12:51 +02003041 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003042
3043 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003044 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003045 }
3046
3047 /*
3048 * Arguments to signal handler:
3049 *
3050 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003051 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003052 * a2 = pointer to struct ucontext
3053 *
3054 * $25 and PC point to the signal handler, $29 points to the
3055 * struct sigframe.
3056 */
3057 env->active_tc.gpr[ 4] = sig;
3058 env->active_tc.gpr[ 5] = frame_addr
3059 + offsetof(struct target_rt_sigframe, rs_info);
3060 env->active_tc.gpr[ 6] = frame_addr
3061 + offsetof(struct target_rt_sigframe, rs_uc);
3062 env->active_tc.gpr[29] = frame_addr;
3063 env->active_tc.gpr[31] = frame_addr
3064 + offsetof(struct target_rt_sigframe, rs_code);
3065 /* The original kernel code sets CP0_EPC to the handler
3066 * since it returns to userland using eret
3067 * we cannot do this here, and we must set PC directly */
3068 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003069 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003070 unlock_user_struct(frame, frame_addr, 1);
3071 return;
3072
3073give_sigsegv:
3074 unlock_user_struct(frame, frame_addr, 1);
3075 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003076}
3077
Andreas Färber05390242012-02-25 03:37:53 +01003078long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003079{
pbrook0b1bcb02009-04-21 01:41:10 +00003080 struct target_rt_sigframe *frame;
3081 abi_ulong frame_addr;
3082 sigset_t blocked;
3083
3084#if defined(DEBUG_SIGNAL)
3085 fprintf(stderr, "do_rt_sigreturn\n");
3086#endif
3087 frame_addr = env->active_tc.gpr[29];
3088 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3089 goto badframe;
3090
Aurelien Jarno60e99242010-03-29 02:12:51 +02003091 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
pbrook0b1bcb02009-04-21 01:41:10 +00003092 sigprocmask(SIG_SETMASK, &blocked, NULL);
3093
Aurelien Jarno60e99242010-03-29 02:12:51 +02003094 if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
pbrook0b1bcb02009-04-21 01:41:10 +00003095 goto badframe;
3096
3097 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003098 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003099 0, get_sp_from_cpustate(env)) == -EFAULT)
3100 goto badframe;
3101
3102 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003103 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003104 /* I am not sure this is right, but it seems to work
3105 * maybe a problem with nested signals ? */
3106 env->CP0_EPC = 0;
3107 return -TARGET_QEMU_ESIGRETURN;
3108
3109badframe:
3110 force_sig(TARGET_SIGSEGV/*, current*/);
3111 return 0;
bellard106ec872006-06-27 21:08:10 +00003112}
bellard6d5e2162004-09-30 22:04:13 +00003113
thsc3b5bc82007-12-02 06:31:25 +00003114#elif defined(TARGET_SH4)
3115
3116/*
3117 * code and data structures from linux kernel:
3118 * include/asm-sh/sigcontext.h
3119 * arch/sh/kernel/signal.c
3120 */
3121
3122struct target_sigcontext {
3123 target_ulong oldmask;
3124
3125 /* CPU registers */
3126 target_ulong sc_gregs[16];
3127 target_ulong sc_pc;
3128 target_ulong sc_pr;
3129 target_ulong sc_sr;
3130 target_ulong sc_gbr;
3131 target_ulong sc_mach;
3132 target_ulong sc_macl;
3133
3134 /* FPU registers */
3135 target_ulong sc_fpregs[16];
3136 target_ulong sc_xfpregs[16];
3137 unsigned int sc_fpscr;
3138 unsigned int sc_fpul;
3139 unsigned int sc_ownedfp;
3140};
3141
3142struct target_sigframe
3143{
3144 struct target_sigcontext sc;
3145 target_ulong extramask[TARGET_NSIG_WORDS-1];
3146 uint16_t retcode[3];
3147};
3148
3149
3150struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003151 target_ulong tuc_flags;
3152 struct target_ucontext *tuc_link;
3153 target_stack_t tuc_stack;
3154 struct target_sigcontext tuc_mcontext;
3155 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003156};
3157
3158struct target_rt_sigframe
3159{
3160 struct target_siginfo info;
3161 struct target_ucontext uc;
3162 uint16_t retcode[3];
3163};
3164
3165
3166#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3167#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3168
pbrook624f7972008-05-31 16:11:38 +00003169static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003170 unsigned long sp, size_t frame_size)
3171{
pbrook624f7972008-05-31 16:11:38 +00003172 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003173 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3174 }
3175
3176 return (sp - frame_size) & -8ul;
3177}
3178
3179static int setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003180 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003181{
3182 int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003183 int i;
thsc3b5bc82007-12-02 06:31:25 +00003184
3185#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
3186 COPY(gregs[0]); COPY(gregs[1]);
3187 COPY(gregs[2]); COPY(gregs[3]);
3188 COPY(gregs[4]); COPY(gregs[5]);
3189 COPY(gregs[6]); COPY(gregs[7]);
3190 COPY(gregs[8]); COPY(gregs[9]);
3191 COPY(gregs[10]); COPY(gregs[11]);
3192 COPY(gregs[12]); COPY(gregs[13]);
3193 COPY(gregs[14]); COPY(gregs[15]);
3194 COPY(gbr); COPY(mach);
3195 COPY(macl); COPY(pr);
3196 COPY(sr); COPY(pc);
3197#undef COPY
3198
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003199 for (i=0; i<16; i++) {
3200 err |= __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
3201 }
3202 err |= __put_user(regs->fpscr, &sc->sc_fpscr);
3203 err |= __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003204
3205 /* non-iBCS2 extensions.. */
3206 err |= __put_user(mask, &sc->oldmask);
3207
3208 return err;
3209}
3210
Andreas Färber05390242012-02-25 03:37:53 +01003211static int restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003212 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003213{
3214 unsigned int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003215 int i;
thsc3b5bc82007-12-02 06:31:25 +00003216
3217#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
3218 COPY(gregs[1]);
3219 COPY(gregs[2]); COPY(gregs[3]);
3220 COPY(gregs[4]); COPY(gregs[5]);
3221 COPY(gregs[6]); COPY(gregs[7]);
3222 COPY(gregs[8]); COPY(gregs[9]);
3223 COPY(gregs[10]); COPY(gregs[11]);
3224 COPY(gregs[12]); COPY(gregs[13]);
3225 COPY(gregs[14]); COPY(gregs[15]);
3226 COPY(gbr); COPY(mach);
3227 COPY(macl); COPY(pr);
3228 COPY(sr); COPY(pc);
3229#undef COPY
3230
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003231 for (i=0; i<16; i++) {
3232 err |= __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
3233 }
3234 err |= __get_user(regs->fpscr, &sc->sc_fpscr);
3235 err |= __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003236
3237 regs->tra = -1; /* disable syscall checks */
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003238 err |= __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003239 return err;
3240}
3241
pbrook624f7972008-05-31 16:11:38 +00003242static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003243 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003244{
3245 struct target_sigframe *frame;
3246 abi_ulong frame_addr;
3247 int i;
3248 int err = 0;
3249 int signal;
3250
3251 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3252 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3253 goto give_sigsegv;
3254
3255 signal = current_exec_domain_sig(sig);
3256
3257 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
3258
3259 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
3260 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
3261 }
3262
3263 /* Set up to return from userspace. If provided, use a stub
3264 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003265 if (ka->sa_flags & TARGET_SA_RESTORER) {
3266 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003267 } else {
3268 /* Generate return code (system call to sigreturn) */
3269 err |= __put_user(MOVW(2), &frame->retcode[0]);
3270 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3271 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
3272 regs->pr = (unsigned long) frame->retcode;
3273 }
3274
3275 if (err)
3276 goto give_sigsegv;
3277
3278 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003279 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003280 regs->gregs[4] = signal; /* Arg for signal handler */
3281 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003282 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003283 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003284
3285 unlock_user_struct(frame, frame_addr, 1);
3286 return;
3287
3288give_sigsegv:
3289 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003290 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003291}
3292
pbrook624f7972008-05-31 16:11:38 +00003293static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003294 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003295 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003296{
3297 struct target_rt_sigframe *frame;
3298 abi_ulong frame_addr;
3299 int i;
3300 int err = 0;
3301 int signal;
3302
3303 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3304 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3305 goto give_sigsegv;
3306
3307 signal = current_exec_domain_sig(sig);
3308
3309 err |= copy_siginfo_to_user(&frame->info, info);
3310
3311 /* Create the ucontext. */
Aurelien Jarno60e99242010-03-29 02:12:51 +02003312 err |= __put_user(0, &frame->uc.tuc_flags);
3313 err |= __put_user(0, (unsigned long *)&frame->uc.tuc_link);
balrog526ccb72008-07-16 12:13:52 +00003314 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003315 &frame->uc.tuc_stack.ss_sp);
thsc3b5bc82007-12-02 06:31:25 +00003316 err |= __put_user(sas_ss_flags(regs->gregs[15]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003317 &frame->uc.tuc_stack.ss_flags);
thsc3b5bc82007-12-02 06:31:25 +00003318 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003319 &frame->uc.tuc_stack.ss_size);
3320 err |= setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003321 regs, set->sig[0]);
3322 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003323 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003324 }
3325
3326 /* Set up to return from userspace. If provided, use a stub
3327 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003328 if (ka->sa_flags & TARGET_SA_RESTORER) {
3329 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003330 } else {
3331 /* Generate return code (system call to sigreturn) */
3332 err |= __put_user(MOVW(2), &frame->retcode[0]);
3333 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3334 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
3335 regs->pr = (unsigned long) frame->retcode;
3336 }
3337
3338 if (err)
3339 goto give_sigsegv;
3340
3341 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003342 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003343 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003344 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3345 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003346 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003347
3348 unlock_user_struct(frame, frame_addr, 1);
3349 return;
3350
3351give_sigsegv:
3352 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003353 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003354}
3355
Andreas Färber05390242012-02-25 03:37:53 +01003356long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003357{
3358 struct target_sigframe *frame;
3359 abi_ulong frame_addr;
3360 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003361 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003362 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003363 int i;
3364 int err = 0;
3365
3366#if defined(DEBUG_SIGNAL)
3367 fprintf(stderr, "do_sigreturn\n");
3368#endif
3369 frame_addr = regs->gregs[15];
3370 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3371 goto badframe;
3372
3373 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
3374 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3375 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
3376 }
3377
3378 if (err)
3379 goto badframe;
3380
3381 target_to_host_sigset_internal(&blocked, &target_set);
3382 sigprocmask(SIG_SETMASK, &blocked, NULL);
3383
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003384 if (restore_sigcontext(regs, &frame->sc, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003385 goto badframe;
3386
3387 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003388 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003389
3390badframe:
3391 unlock_user_struct(frame, frame_addr, 0);
3392 force_sig(TARGET_SIGSEGV);
3393 return 0;
3394}
3395
Andreas Färber05390242012-02-25 03:37:53 +01003396long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003397{
3398 struct target_rt_sigframe *frame;
3399 abi_ulong frame_addr;
3400 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003401 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003402
3403#if defined(DEBUG_SIGNAL)
3404 fprintf(stderr, "do_rt_sigreturn\n");
3405#endif
3406 frame_addr = regs->gregs[15];
3407 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3408 goto badframe;
3409
Aurelien Jarno60e99242010-03-29 02:12:51 +02003410 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
thsc3b5bc82007-12-02 06:31:25 +00003411 sigprocmask(SIG_SETMASK, &blocked, NULL);
3412
Aurelien Jarno60e99242010-03-29 02:12:51 +02003413 if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003414 goto badframe;
3415
3416 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003417 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003418 0, get_sp_from_cpustate(regs)) == -EFAULT)
3419 goto badframe;
3420
3421 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003422 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003423
3424badframe:
3425 unlock_user_struct(frame, frame_addr, 0);
3426 force_sig(TARGET_SIGSEGV);
3427 return 0;
3428}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003429#elif defined(TARGET_MICROBLAZE)
3430
3431struct target_sigcontext {
3432 struct target_pt_regs regs; /* needs to be first */
3433 uint32_t oldmask;
3434};
3435
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003436struct target_stack_t {
3437 abi_ulong ss_sp;
3438 int ss_flags;
3439 unsigned int ss_size;
3440};
3441
3442struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003443 abi_ulong tuc_flags;
3444 abi_ulong tuc_link;
3445 struct target_stack_t tuc_stack;
3446 struct target_sigcontext tuc_mcontext;
3447 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003448};
3449
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003450/* Signal frames. */
3451struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003452 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003453 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3454 uint32_t tramp[2];
3455};
3456
3457struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003458 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003459 struct ucontext uc;
3460 uint32_t tramp[2];
3461};
3462
Andreas Färber05390242012-02-25 03:37:53 +01003463static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003464{
3465 __put_user(env->regs[0], &sc->regs.r0);
3466 __put_user(env->regs[1], &sc->regs.r1);
3467 __put_user(env->regs[2], &sc->regs.r2);
3468 __put_user(env->regs[3], &sc->regs.r3);
3469 __put_user(env->regs[4], &sc->regs.r4);
3470 __put_user(env->regs[5], &sc->regs.r5);
3471 __put_user(env->regs[6], &sc->regs.r6);
3472 __put_user(env->regs[7], &sc->regs.r7);
3473 __put_user(env->regs[8], &sc->regs.r8);
3474 __put_user(env->regs[9], &sc->regs.r9);
3475 __put_user(env->regs[10], &sc->regs.r10);
3476 __put_user(env->regs[11], &sc->regs.r11);
3477 __put_user(env->regs[12], &sc->regs.r12);
3478 __put_user(env->regs[13], &sc->regs.r13);
3479 __put_user(env->regs[14], &sc->regs.r14);
3480 __put_user(env->regs[15], &sc->regs.r15);
3481 __put_user(env->regs[16], &sc->regs.r16);
3482 __put_user(env->regs[17], &sc->regs.r17);
3483 __put_user(env->regs[18], &sc->regs.r18);
3484 __put_user(env->regs[19], &sc->regs.r19);
3485 __put_user(env->regs[20], &sc->regs.r20);
3486 __put_user(env->regs[21], &sc->regs.r21);
3487 __put_user(env->regs[22], &sc->regs.r22);
3488 __put_user(env->regs[23], &sc->regs.r23);
3489 __put_user(env->regs[24], &sc->regs.r24);
3490 __put_user(env->regs[25], &sc->regs.r25);
3491 __put_user(env->regs[26], &sc->regs.r26);
3492 __put_user(env->regs[27], &sc->regs.r27);
3493 __put_user(env->regs[28], &sc->regs.r28);
3494 __put_user(env->regs[29], &sc->regs.r29);
3495 __put_user(env->regs[30], &sc->regs.r30);
3496 __put_user(env->regs[31], &sc->regs.r31);
3497 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3498}
3499
Andreas Färber05390242012-02-25 03:37:53 +01003500static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003501{
3502 __get_user(env->regs[0], &sc->regs.r0);
3503 __get_user(env->regs[1], &sc->regs.r1);
3504 __get_user(env->regs[2], &sc->regs.r2);
3505 __get_user(env->regs[3], &sc->regs.r3);
3506 __get_user(env->regs[4], &sc->regs.r4);
3507 __get_user(env->regs[5], &sc->regs.r5);
3508 __get_user(env->regs[6], &sc->regs.r6);
3509 __get_user(env->regs[7], &sc->regs.r7);
3510 __get_user(env->regs[8], &sc->regs.r8);
3511 __get_user(env->regs[9], &sc->regs.r9);
3512 __get_user(env->regs[10], &sc->regs.r10);
3513 __get_user(env->regs[11], &sc->regs.r11);
3514 __get_user(env->regs[12], &sc->regs.r12);
3515 __get_user(env->regs[13], &sc->regs.r13);
3516 __get_user(env->regs[14], &sc->regs.r14);
3517 __get_user(env->regs[15], &sc->regs.r15);
3518 __get_user(env->regs[16], &sc->regs.r16);
3519 __get_user(env->regs[17], &sc->regs.r17);
3520 __get_user(env->regs[18], &sc->regs.r18);
3521 __get_user(env->regs[19], &sc->regs.r19);
3522 __get_user(env->regs[20], &sc->regs.r20);
3523 __get_user(env->regs[21], &sc->regs.r21);
3524 __get_user(env->regs[22], &sc->regs.r22);
3525 __get_user(env->regs[23], &sc->regs.r23);
3526 __get_user(env->regs[24], &sc->regs.r24);
3527 __get_user(env->regs[25], &sc->regs.r25);
3528 __get_user(env->regs[26], &sc->regs.r26);
3529 __get_user(env->regs[27], &sc->regs.r27);
3530 __get_user(env->regs[28], &sc->regs.r28);
3531 __get_user(env->regs[29], &sc->regs.r29);
3532 __get_user(env->regs[30], &sc->regs.r30);
3533 __get_user(env->regs[31], &sc->regs.r31);
3534 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3535}
3536
3537static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003538 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003539{
3540 abi_ulong sp = env->regs[1];
3541
3542 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3543 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3544
3545 return ((sp - frame_size) & -8UL);
3546}
3547
3548static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003549 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003550{
3551 struct target_signal_frame *frame;
3552 abi_ulong frame_addr;
3553 int err = 0;
3554 int i;
3555
3556 frame_addr = get_sigframe(ka, env, sizeof *frame);
3557 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3558 goto badframe;
3559
3560 /* Save the mask. */
Richard Hendersonf711df62010-11-22 14:57:52 -08003561 err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003562 if (err)
3563 goto badframe;
3564
3565 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3566 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3567 goto badframe;
3568 }
3569
Richard Hendersonf711df62010-11-22 14:57:52 -08003570 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003571
3572 /* Set up to return from userspace. If provided, use a stub
3573 already in userspace. */
3574 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3575 if (ka->sa_flags & TARGET_SA_RESTORER) {
3576 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3577 } else {
3578 uint32_t t;
3579 /* Note, these encodings are _big endian_! */
3580 /* addi r12, r0, __NR_sigreturn */
3581 t = 0x31800000UL | TARGET_NR_sigreturn;
3582 err |= __put_user(t, frame->tramp + 0);
3583 /* brki r14, 0x8 */
3584 t = 0xb9cc0008UL;
3585 err |= __put_user(t, frame->tramp + 1);
3586
3587 /* Return from sighandler will jump to the tramp.
3588 Negative 8 offset because return is rtsd r15, 8 */
3589 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3590 }
3591
3592 if (err)
3593 goto badframe;
3594
3595 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003596 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003597 /* Signal handler args: */
3598 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003599 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003600 /* arg 1: sigcontext */
3601 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003602
3603 /* Offset of 4 to handle microblaze rtid r14, 0 */
3604 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3605
3606 unlock_user_struct(frame, frame_addr, 1);
3607 return;
3608 badframe:
3609 unlock_user_struct(frame, frame_addr, 1);
3610 force_sig(TARGET_SIGSEGV);
3611}
3612
3613static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003614 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003615 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003616{
3617 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3618}
3619
Andreas Färber05390242012-02-25 03:37:53 +01003620long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003621{
3622 struct target_signal_frame *frame;
3623 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003624 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003625 sigset_t set;
3626 int i;
3627
3628 frame_addr = env->regs[R_SP];
3629 /* Make sure the guest isn't playing games. */
3630 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3631 goto badframe;
3632
3633 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003634 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003635 goto badframe;
3636 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3637 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3638 goto badframe;
3639 }
3640 target_to_host_sigset_internal(&set, &target_set);
3641 sigprocmask(SIG_SETMASK, &set, NULL);
3642
Richard Hendersonf711df62010-11-22 14:57:52 -08003643 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003644 /* We got here through a sigreturn syscall, our path back is via an
3645 rtb insn so setup r14 for that. */
3646 env->regs[14] = env->sregs[SR_PC];
3647
3648 unlock_user_struct(frame, frame_addr, 0);
3649 return env->regs[10];
3650 badframe:
3651 unlock_user_struct(frame, frame_addr, 0);
3652 force_sig(TARGET_SIGSEGV);
3653}
3654
Andreas Färber05390242012-02-25 03:37:53 +01003655long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003656{
3657 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3658 return -TARGET_ENOSYS;
3659}
3660
edgar_iglb6d3abd2008-02-28 11:29:27 +00003661#elif defined(TARGET_CRIS)
3662
3663struct target_sigcontext {
3664 struct target_pt_regs regs; /* needs to be first */
3665 uint32_t oldmask;
3666 uint32_t usp; /* usp before stacking this gunk on it */
3667};
3668
3669/* Signal frames. */
3670struct target_signal_frame {
3671 struct target_sigcontext sc;
3672 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003673 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003674};
3675
3676struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003677 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003678 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003679 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003680 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003681 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003682};
3683
Andreas Färber05390242012-02-25 03:37:53 +01003684static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003685{
edgar_igl9664d922008-03-03 22:23:53 +00003686 __put_user(env->regs[0], &sc->regs.r0);
3687 __put_user(env->regs[1], &sc->regs.r1);
3688 __put_user(env->regs[2], &sc->regs.r2);
3689 __put_user(env->regs[3], &sc->regs.r3);
3690 __put_user(env->regs[4], &sc->regs.r4);
3691 __put_user(env->regs[5], &sc->regs.r5);
3692 __put_user(env->regs[6], &sc->regs.r6);
3693 __put_user(env->regs[7], &sc->regs.r7);
3694 __put_user(env->regs[8], &sc->regs.r8);
3695 __put_user(env->regs[9], &sc->regs.r9);
3696 __put_user(env->regs[10], &sc->regs.r10);
3697 __put_user(env->regs[11], &sc->regs.r11);
3698 __put_user(env->regs[12], &sc->regs.r12);
3699 __put_user(env->regs[13], &sc->regs.r13);
3700 __put_user(env->regs[14], &sc->usp);
3701 __put_user(env->regs[15], &sc->regs.acr);
3702 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3703 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3704 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003705}
edgar_igl9664d922008-03-03 22:23:53 +00003706
Andreas Färber05390242012-02-25 03:37:53 +01003707static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003708{
edgar_igl9664d922008-03-03 22:23:53 +00003709 __get_user(env->regs[0], &sc->regs.r0);
3710 __get_user(env->regs[1], &sc->regs.r1);
3711 __get_user(env->regs[2], &sc->regs.r2);
3712 __get_user(env->regs[3], &sc->regs.r3);
3713 __get_user(env->regs[4], &sc->regs.r4);
3714 __get_user(env->regs[5], &sc->regs.r5);
3715 __get_user(env->regs[6], &sc->regs.r6);
3716 __get_user(env->regs[7], &sc->regs.r7);
3717 __get_user(env->regs[8], &sc->regs.r8);
3718 __get_user(env->regs[9], &sc->regs.r9);
3719 __get_user(env->regs[10], &sc->regs.r10);
3720 __get_user(env->regs[11], &sc->regs.r11);
3721 __get_user(env->regs[12], &sc->regs.r12);
3722 __get_user(env->regs[13], &sc->regs.r13);
3723 __get_user(env->regs[14], &sc->usp);
3724 __get_user(env->regs[15], &sc->regs.acr);
3725 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3726 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3727 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003728}
3729
Andreas Färber05390242012-02-25 03:37:53 +01003730static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003731{
edgar_igl9664d922008-03-03 22:23:53 +00003732 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003733 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003734 sp = (env->regs[R_SP] & ~3);
3735 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003736}
3737
pbrook624f7972008-05-31 16:11:38 +00003738static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003739 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003740{
3741 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003742 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003743 int err = 0;
3744 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003745
edgar_igl9664d922008-03-03 22:23:53 +00003746 frame_addr = get_sigframe(env, sizeof *frame);
3747 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003748 goto badframe;
3749
3750 /*
3751 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3752 * use this trampoline anymore but it sets it up for GDB.
3753 * In QEMU, using the trampoline simplifies things a bit so we use it.
3754 *
3755 * This is movu.w __NR_sigreturn, r9; break 13;
3756 */
3757 err |= __put_user(0x9c5f, frame->retcode+0);
3758 err |= __put_user(TARGET_NR_sigreturn,
Stefan Weil8cfc1142014-02-01 09:41:09 +01003759 frame->retcode + 1);
3760 err |= __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003761
3762 /* Save the mask. */
3763 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3764 if (err)
3765 goto badframe;
3766
3767 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3768 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3769 goto badframe;
3770 }
3771
3772 setup_sigcontext(&frame->sc, env);
3773
3774 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003775 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003776 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003777 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003778 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003779 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003780
edgar_igl9664d922008-03-03 22:23:53 +00003781 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003782 return;
3783 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003784 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003785 force_sig(TARGET_SIGSEGV);
3786}
3787
pbrook624f7972008-05-31 16:11:38 +00003788static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003789 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003790 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003791{
3792 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3793}
3794
Andreas Färber05390242012-02-25 03:37:53 +01003795long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003796{
3797 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003798 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003799 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003800 sigset_t set;
3801 int i;
3802
edgar_igl9664d922008-03-03 22:23:53 +00003803 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003804 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003805 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003806 goto badframe;
3807
3808 /* Restore blocked signals */
3809 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3810 goto badframe;
3811 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3812 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3813 goto badframe;
3814 }
3815 target_to_host_sigset_internal(&set, &target_set);
3816 sigprocmask(SIG_SETMASK, &set, NULL);
3817
3818 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003819 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003820 return env->regs[10];
3821 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003822 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003823 force_sig(TARGET_SIGSEGV);
3824}
3825
Andreas Färber05390242012-02-25 03:37:53 +01003826long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003827{
3828 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3829 return -TARGET_ENOSYS;
3830}
thsc3b5bc82007-12-02 06:31:25 +00003831
Jia Liud9627832012-07-20 15:50:52 +08003832#elif defined(TARGET_OPENRISC)
3833
3834struct target_sigcontext {
3835 struct target_pt_regs regs;
3836 abi_ulong oldmask;
3837 abi_ulong usp;
3838};
3839
3840struct target_ucontext {
3841 abi_ulong tuc_flags;
3842 abi_ulong tuc_link;
3843 target_stack_t tuc_stack;
3844 struct target_sigcontext tuc_mcontext;
3845 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3846};
3847
3848struct target_rt_sigframe {
3849 abi_ulong pinfo;
3850 uint64_t puc;
3851 struct target_siginfo info;
3852 struct target_sigcontext sc;
3853 struct target_ucontext uc;
3854 unsigned char retcode[16]; /* trampoline code */
3855};
3856
3857/* This is the asm-generic/ucontext.h version */
3858#if 0
3859static int restore_sigcontext(CPUOpenRISCState *regs,
3860 struct target_sigcontext *sc)
3861{
3862 unsigned int err = 0;
3863 unsigned long old_usp;
3864
3865 /* Alwys make any pending restarted system call return -EINTR */
3866 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3867
3868 /* restore the regs from &sc->regs (same as sc, since regs is first)
3869 * (sc is already checked for VERIFY_READ since the sigframe was
3870 * checked in sys_sigreturn previously)
3871 */
3872
3873 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3874 goto badframe;
3875 }
3876
3877 /* make sure the U-flag is set so user-mode cannot fool us */
3878
3879 regs->sr &= ~SR_SM;
3880
3881 /* restore the old USP as it was before we stacked the sc etc.
3882 * (we cannot just pop the sigcontext since we aligned the sp and
3883 * stuff after pushing it)
3884 */
3885
3886 err |= __get_user(old_usp, &sc->usp);
3887 phx_signal("old_usp 0x%lx", old_usp);
3888
3889 __PHX__ REALLY /* ??? */
3890 wrusp(old_usp);
3891 regs->gpr[1] = old_usp;
3892
3893 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3894 * after this completes, but we don't use that mechanism. maybe we can
3895 * use it now ?
3896 */
3897
3898 return err;
3899
3900badframe:
3901 return 1;
3902}
3903#endif
3904
3905/* Set up a signal frame. */
3906
3907static int setup_sigcontext(struct target_sigcontext *sc,
3908 CPUOpenRISCState *regs,
3909 unsigned long mask)
3910{
3911 int err = 0;
3912 unsigned long usp = regs->gpr[1];
3913
3914 /* copy the regs. they are first in sc so we can use sc directly */
3915
3916 /*err |= copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
3917
3918 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3919 the signal handler. The frametype will be restored to its previous
3920 value in restore_sigcontext. */
3921 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3922
3923 /* then some other stuff */
3924 err |= __put_user(mask, &sc->oldmask);
3925 err |= __put_user(usp, &sc->usp); return err;
3926}
3927
3928static inline unsigned long align_sigframe(unsigned long sp)
3929{
3930 unsigned long i;
3931 i = sp & ~3UL;
3932 return i;
3933}
3934
3935static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3936 CPUOpenRISCState *regs,
3937 size_t frame_size)
3938{
3939 unsigned long sp = regs->gpr[1];
3940 int onsigstack = on_sig_stack(sp);
3941
3942 /* redzone */
3943 /* This is the X/Open sanctioned signal stack switching. */
3944 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3945 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3946 }
3947
3948 sp = align_sigframe(sp - frame_size);
3949
3950 /*
3951 * If we are on the alternate signal stack and would overflow it, don't.
3952 * Return an always-bogus address instead so we will die with SIGSEGV.
3953 */
3954
3955 if (onsigstack && !likely(on_sig_stack(sp))) {
3956 return -1L;
3957 }
3958
3959 return sp;
3960}
3961
3962static void setup_frame(int sig, struct target_sigaction *ka,
3963 target_sigset_t *set, CPUOpenRISCState *env)
3964{
3965 qemu_log("Not implement.\n");
3966}
3967
3968static void setup_rt_frame(int sig, struct target_sigaction *ka,
3969 target_siginfo_t *info,
3970 target_sigset_t *set, CPUOpenRISCState *env)
3971{
3972 int err = 0;
3973 abi_ulong frame_addr;
3974 unsigned long return_ip;
3975 struct target_rt_sigframe *frame;
3976 abi_ulong info_addr, uc_addr;
3977
3978 frame_addr = get_sigframe(ka, env, sizeof *frame);
3979
3980 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3981 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3982 goto give_sigsegv;
3983 }
3984
3985 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
3986 err |= __put_user(info_addr, &frame->pinfo);
3987 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
3988 err |= __put_user(uc_addr, &frame->puc);
3989
3990 if (ka->sa_flags & SA_SIGINFO) {
3991 err |= copy_siginfo_to_user(&frame->info, info);
3992 }
3993 if (err) {
3994 goto give_sigsegv;
3995 }
3996
3997 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
3998 err |= __put_user(0, &frame->uc.tuc_flags);
3999 err |= __put_user(0, &frame->uc.tuc_link);
4000 err |= __put_user(target_sigaltstack_used.ss_sp,
4001 &frame->uc.tuc_stack.ss_sp);
4002 err |= __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
4003 err |= __put_user(target_sigaltstack_used.ss_size,
4004 &frame->uc.tuc_stack.ss_size);
4005 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
4006
4007 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4008
4009 if (err) {
4010 goto give_sigsegv;
4011 }
4012
4013 /* trampoline - the desired return ip is the retcode itself */
4014 return_ip = (unsigned long)&frame->retcode;
4015 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
4016 err |= __put_user(0xa960, (short *)(frame->retcode + 0));
4017 err |= __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4018 err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4019 err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
4020
4021 if (err) {
4022 goto give_sigsegv;
4023 }
4024
4025 /* TODO what is the current->exec_domain stuff and invmap ? */
4026
4027 /* Set up registers for signal handler */
4028 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4029 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4030 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4031 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4032 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4033
4034 /* actually move the usp to reflect the stacked frame */
4035 env->gpr[1] = (unsigned long)frame;
4036
4037 return;
4038
4039give_sigsegv:
4040 unlock_user_struct(frame, frame_addr, 1);
4041 if (sig == TARGET_SIGSEGV) {
4042 ka->_sa_handler = TARGET_SIG_DFL;
4043 }
4044 force_sig(TARGET_SIGSEGV);
4045}
4046
4047long do_sigreturn(CPUOpenRISCState *env)
4048{
4049
4050 qemu_log("do_sigreturn: not implemented\n");
4051 return -TARGET_ENOSYS;
4052}
4053
4054long do_rt_sigreturn(CPUOpenRISCState *env)
4055{
4056 qemu_log("do_rt_sigreturn: not implemented\n");
4057 return -TARGET_ENOSYS;
4058}
4059/* TARGET_OPENRISC */
4060
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004061#elif defined(TARGET_S390X)
4062
4063#define __NUM_GPRS 16
4064#define __NUM_FPRS 16
4065#define __NUM_ACRS 16
4066
4067#define S390_SYSCALL_SIZE 2
4068#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4069
4070#define _SIGCONTEXT_NSIG 64
4071#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4072#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4073#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4074#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4075#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4076
4077typedef struct {
4078 target_psw_t psw;
4079 target_ulong gprs[__NUM_GPRS];
4080 unsigned int acrs[__NUM_ACRS];
4081} target_s390_regs_common;
4082
4083typedef struct {
4084 unsigned int fpc;
4085 double fprs[__NUM_FPRS];
4086} target_s390_fp_regs;
4087
4088typedef struct {
4089 target_s390_regs_common regs;
4090 target_s390_fp_regs fpregs;
4091} target_sigregs;
4092
4093struct target_sigcontext {
4094 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4095 target_sigregs *sregs;
4096};
4097
4098typedef struct {
4099 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4100 struct target_sigcontext sc;
4101 target_sigregs sregs;
4102 int signo;
4103 uint8_t retcode[S390_SYSCALL_SIZE];
4104} sigframe;
4105
4106struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004107 target_ulong tuc_flags;
4108 struct target_ucontext *tuc_link;
4109 target_stack_t tuc_stack;
4110 target_sigregs tuc_mcontext;
4111 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004112};
4113
4114typedef struct {
4115 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4116 uint8_t retcode[S390_SYSCALL_SIZE];
4117 struct target_siginfo info;
4118 struct target_ucontext uc;
4119} rt_sigframe;
4120
4121static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004122get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004123{
4124 abi_ulong sp;
4125
4126 /* Default to using normal stack */
4127 sp = env->regs[15];
4128
4129 /* This is the X/Open sanctioned signal stack switching. */
4130 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4131 if (!sas_ss_flags(sp)) {
4132 sp = target_sigaltstack_used.ss_sp +
4133 target_sigaltstack_used.ss_size;
4134 }
4135 }
4136
4137 /* This is the legacy signal stack switching. */
4138 else if (/* FIXME !user_mode(regs) */ 0 &&
4139 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4140 ka->sa_restorer) {
4141 sp = (abi_ulong) ka->sa_restorer;
4142 }
4143
4144 return (sp - frame_size) & -8ul;
4145}
4146
Andreas Färber05390242012-02-25 03:37:53 +01004147static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004148{
4149 int i;
4150 //save_access_regs(current->thread.acrs); FIXME
4151
4152 /* Copy a 'clean' PSW mask to the user to avoid leaking
4153 information about whether PER is currently on. */
4154 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4155 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4156 for (i = 0; i < 16; i++) {
4157 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4158 }
4159 for (i = 0; i < 16; i++) {
4160 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4161 }
4162 /*
4163 * We have to store the fp registers to current->thread.fp_regs
4164 * to merge them with the emulated registers.
4165 */
4166 //save_fp_regs(&current->thread.fp_regs); FIXME
4167 for (i = 0; i < 16; i++) {
4168 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4169 }
4170}
4171
4172static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004173 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004174{
4175 sigframe *frame;
4176 abi_ulong frame_addr;
4177
4178 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4179 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4180 (unsigned long long)frame_addr);
4181 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4182 goto give_sigsegv;
4183 }
4184
4185 qemu_log("%s: 1\n", __FUNCTION__);
4186 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
4187 goto give_sigsegv;
4188 }
4189
4190 save_sigregs(env, &frame->sregs);
4191
4192 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4193 (abi_ulong *)&frame->sc.sregs);
4194
4195 /* Set up to return from userspace. If provided, use a stub
4196 already in userspace. */
4197 if (ka->sa_flags & TARGET_SA_RESTORER) {
4198 env->regs[14] = (unsigned long)
4199 ka->sa_restorer | PSW_ADDR_AMODE;
4200 } else {
4201 env->regs[14] = (unsigned long)
4202 frame->retcode | PSW_ADDR_AMODE;
4203 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4204 (uint16_t *)(frame->retcode)))
4205 goto give_sigsegv;
4206 }
4207
4208 /* Set up backchain. */
4209 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4210 goto give_sigsegv;
4211 }
4212
4213 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004214 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004215 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4216
4217 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004218 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004219
4220 /* We forgot to include these in the sigcontext.
4221 To avoid breaking binary compatibility, they are passed as args. */
4222 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4223 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4224
4225 /* Place signal number on stack to allow backtrace from handler. */
4226 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4227 goto give_sigsegv;
4228 }
4229 unlock_user_struct(frame, frame_addr, 1);
4230 return;
4231
4232give_sigsegv:
4233 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4234 unlock_user_struct(frame, frame_addr, 1);
4235 force_sig(TARGET_SIGSEGV);
4236}
4237
4238static void setup_rt_frame(int sig, struct target_sigaction *ka,
4239 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004240 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004241{
4242 int i;
4243 rt_sigframe *frame;
4244 abi_ulong frame_addr;
4245
4246 frame_addr = get_sigframe(ka, env, sizeof *frame);
4247 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4248 (unsigned long long)frame_addr);
4249 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4250 goto give_sigsegv;
4251 }
4252
4253 qemu_log("%s: 1\n", __FUNCTION__);
4254 if (copy_siginfo_to_user(&frame->info, info)) {
4255 goto give_sigsegv;
4256 }
4257
4258 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004259 __put_user(0, &frame->uc.tuc_flags);
4260 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4261 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004262 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004263 &frame->uc.tuc_stack.ss_flags);
4264 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4265 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004266 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4267 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004268 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004269 }
4270
4271 /* Set up to return from userspace. If provided, use a stub
4272 already in userspace. */
4273 if (ka->sa_flags & TARGET_SA_RESTORER) {
4274 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4275 } else {
4276 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4277 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4278 (uint16_t *)(frame->retcode))) {
4279 goto give_sigsegv;
4280 }
4281 }
4282
4283 /* Set up backchain. */
4284 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4285 goto give_sigsegv;
4286 }
4287
4288 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004289 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004290 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4291
4292 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004293 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4294 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004295 return;
4296
4297give_sigsegv:
4298 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4299 unlock_user_struct(frame, frame_addr, 1);
4300 force_sig(TARGET_SIGSEGV);
4301}
4302
4303static int
Andreas Färber05390242012-02-25 03:37:53 +01004304restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004305{
4306 int err = 0;
4307 int i;
4308
4309 for (i = 0; i < 16; i++) {
4310 err |= __get_user(env->regs[i], &sc->regs.gprs[i]);
4311 }
4312
4313 err |= __get_user(env->psw.mask, &sc->regs.psw.mask);
4314 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4315 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4316 (unsigned long long)env->psw.addr);
4317 err |= __get_user(env->psw.addr, &sc->regs.psw.addr);
4318 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4319
4320 for (i = 0; i < 16; i++) {
4321 err |= __get_user(env->aregs[i], &sc->regs.acrs[i]);
4322 }
4323 for (i = 0; i < 16; i++) {
4324 err |= __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
4325 }
4326
4327 return err;
4328}
4329
Andreas Färber05390242012-02-25 03:37:53 +01004330long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004331{
4332 sigframe *frame;
4333 abi_ulong frame_addr = env->regs[15];
4334 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4335 (unsigned long long)frame_addr);
4336 target_sigset_t target_set;
4337 sigset_t set;
4338
4339 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4340 goto badframe;
4341 }
4342 if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
4343 goto badframe;
4344 }
4345
4346 target_to_host_sigset_internal(&set, &target_set);
4347 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4348
4349 if (restore_sigregs(env, &frame->sregs)) {
4350 goto badframe;
4351 }
4352
4353 unlock_user_struct(frame, frame_addr, 0);
4354 return env->regs[2];
4355
4356badframe:
4357 unlock_user_struct(frame, frame_addr, 0);
4358 force_sig(TARGET_SIGSEGV);
4359 return 0;
4360}
4361
Andreas Färber05390242012-02-25 03:37:53 +01004362long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004363{
4364 rt_sigframe *frame;
4365 abi_ulong frame_addr = env->regs[15];
4366 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4367 (unsigned long long)frame_addr);
4368 sigset_t set;
4369
4370 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4371 goto badframe;
4372 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004373 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004374
4375 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4376
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004377 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004378 goto badframe;
4379 }
4380
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004381 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004382 get_sp_from_cpustate(env)) == -EFAULT) {
4383 goto badframe;
4384 }
4385 unlock_user_struct(frame, frame_addr, 0);
4386 return env->regs[2];
4387
4388badframe:
4389 unlock_user_struct(frame, frame_addr, 0);
4390 force_sig(TARGET_SIGSEGV);
4391 return 0;
4392}
4393
Nathan Froydbcd49332009-05-12 19:13:18 -07004394#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4395
4396/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4397 the signal handling is different enough that we haven't implemented
4398 support for PPC64 yet. Hence the restriction above.
4399
4400 There are various #if'd blocks for code for TARGET_PPC64. These
4401 blocks should go away so that we can successfully run 32-bit and
4402 64-bit binaries on a QEMU configured for PPC64. */
4403
4404/* Size of dummy stack frame allocated when calling signal handler.
4405 See arch/powerpc/include/asm/ptrace.h. */
4406#if defined(TARGET_PPC64)
4407#define SIGNAL_FRAMESIZE 128
4408#else
4409#define SIGNAL_FRAMESIZE 64
4410#endif
4411
4412/* See arch/powerpc/include/asm/sigcontext.h. */
4413struct target_sigcontext {
4414 target_ulong _unused[4];
4415 int32_t signal;
4416#if defined(TARGET_PPC64)
4417 int32_t pad0;
4418#endif
4419 target_ulong handler;
4420 target_ulong oldmask;
4421 target_ulong regs; /* struct pt_regs __user * */
4422 /* TODO: PPC64 includes extra bits here. */
4423};
4424
4425/* Indices for target_mcontext.mc_gregs, below.
4426 See arch/powerpc/include/asm/ptrace.h for details. */
4427enum {
4428 TARGET_PT_R0 = 0,
4429 TARGET_PT_R1 = 1,
4430 TARGET_PT_R2 = 2,
4431 TARGET_PT_R3 = 3,
4432 TARGET_PT_R4 = 4,
4433 TARGET_PT_R5 = 5,
4434 TARGET_PT_R6 = 6,
4435 TARGET_PT_R7 = 7,
4436 TARGET_PT_R8 = 8,
4437 TARGET_PT_R9 = 9,
4438 TARGET_PT_R10 = 10,
4439 TARGET_PT_R11 = 11,
4440 TARGET_PT_R12 = 12,
4441 TARGET_PT_R13 = 13,
4442 TARGET_PT_R14 = 14,
4443 TARGET_PT_R15 = 15,
4444 TARGET_PT_R16 = 16,
4445 TARGET_PT_R17 = 17,
4446 TARGET_PT_R18 = 18,
4447 TARGET_PT_R19 = 19,
4448 TARGET_PT_R20 = 20,
4449 TARGET_PT_R21 = 21,
4450 TARGET_PT_R22 = 22,
4451 TARGET_PT_R23 = 23,
4452 TARGET_PT_R24 = 24,
4453 TARGET_PT_R25 = 25,
4454 TARGET_PT_R26 = 26,
4455 TARGET_PT_R27 = 27,
4456 TARGET_PT_R28 = 28,
4457 TARGET_PT_R29 = 29,
4458 TARGET_PT_R30 = 30,
4459 TARGET_PT_R31 = 31,
4460 TARGET_PT_NIP = 32,
4461 TARGET_PT_MSR = 33,
4462 TARGET_PT_ORIG_R3 = 34,
4463 TARGET_PT_CTR = 35,
4464 TARGET_PT_LNK = 36,
4465 TARGET_PT_XER = 37,
4466 TARGET_PT_CCR = 38,
4467 /* Yes, there are two registers with #39. One is 64-bit only. */
4468 TARGET_PT_MQ = 39,
4469 TARGET_PT_SOFTE = 39,
4470 TARGET_PT_TRAP = 40,
4471 TARGET_PT_DAR = 41,
4472 TARGET_PT_DSISR = 42,
4473 TARGET_PT_RESULT = 43,
4474 TARGET_PT_REGS_COUNT = 44
4475};
4476
4477/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4478 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4479struct target_mcontext {
4480 target_ulong mc_gregs[48];
4481 /* Includes fpscr. */
4482 uint64_t mc_fregs[33];
4483 target_ulong mc_pad[2];
4484 /* We need to handle Altivec and SPE at the same time, which no
4485 kernel needs to do. Fortunately, the kernel defines this bit to
4486 be Altivec-register-large all the time, rather than trying to
4487 twiddle it based on the specific platform. */
4488 union {
4489 /* SPE vector registers. One extra for SPEFSCR. */
4490 uint32_t spe[33];
4491 /* Altivec vector registers. The packing of VSCR and VRSAVE
4492 varies depending on whether we're PPC64 or not: PPC64 splits
4493 them apart; PPC32 stuffs them together. */
4494#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004495#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004496#else
malc3efa9a62009-07-18 13:10:12 +04004497#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004498#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004499 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004500#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004501 } mc_vregs __attribute__((__aligned__(16)));
4502};
4503
4504struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004505 target_ulong tuc_flags;
4506 target_ulong tuc_link; /* struct ucontext __user * */
4507 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004508#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004509 int32_t tuc_pad[7];
4510 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004511 points to uc_mcontext field */
4512#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004513 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004514#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004515 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004516 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004517#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004518 int32_t tuc_maskext[30];
4519 int32_t tuc_pad2[3];
4520 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004521#endif
4522};
4523
4524/* See arch/powerpc/kernel/signal_32.c. */
4525struct target_sigframe {
4526 struct target_sigcontext sctx;
4527 struct target_mcontext mctx;
4528 int32_t abigap[56];
4529};
4530
4531struct target_rt_sigframe {
4532 struct target_siginfo info;
4533 struct target_ucontext uc;
4534 int32_t abigap[56];
4535};
4536
4537/* We use the mc_pad field for the signal return trampoline. */
4538#define tramp mc_pad
4539
4540/* See arch/powerpc/kernel/signal.c. */
4541static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004542 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004543 int frame_size)
4544{
4545 target_ulong oldsp, newsp;
4546
4547 oldsp = env->gpr[1];
4548
4549 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004550 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004551 oldsp = (target_sigaltstack_used.ss_sp
4552 + target_sigaltstack_used.ss_size);
4553 }
4554
4555 newsp = (oldsp - frame_size) & ~0xFUL;
4556
4557 return newsp;
4558}
4559
Andreas Färber05390242012-02-25 03:37:53 +01004560static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004561 int sigret)
4562{
4563 target_ulong msr = env->msr;
4564 int i;
4565 target_ulong ccr = 0;
4566
4567 /* In general, the kernel attempts to be intelligent about what it
4568 needs to save for Altivec/FP/SPE registers. We don't care that
4569 much, so we just go ahead and save everything. */
4570
4571 /* Save general registers. */
4572 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4573 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4574 return 1;
4575 }
4576 }
4577 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4578 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4579 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4580 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4581 return 1;
4582
4583 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4584 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4585 }
4586 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4587 return 1;
4588
4589 /* Save Altivec registers if necessary. */
4590 if (env->insns_flags & PPC_ALTIVEC) {
4591 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004592 ppc_avr_t *avr = &env->avr[i];
4593 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004594
4595 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4596 __put_user(avr->u64[1], &vreg->u64[1])) {
4597 return 1;
4598 }
4599 }
4600 /* Set MSR_VR in the saved MSR value to indicate that
4601 frame->mc_vregs contains valid data. */
4602 msr |= MSR_VR;
4603 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4604 &frame->mc_vregs.altivec[32].u32[3]))
4605 return 1;
4606 }
4607
4608 /* Save floating point registers. */
4609 if (env->insns_flags & PPC_FLOAT) {
4610 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4611 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4612 return 1;
4613 }
4614 }
4615 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4616 return 1;
4617 }
4618
4619 /* Save SPE registers. The kernel only saves the high half. */
4620 if (env->insns_flags & PPC_SPE) {
4621#if defined(TARGET_PPC64)
4622 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4623 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4624 return 1;
4625 }
4626 }
4627#else
4628 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4629 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4630 return 1;
4631 }
4632 }
4633#endif
4634 /* Set MSR_SPE in the saved MSR value to indicate that
4635 frame->mc_vregs contains valid data. */
4636 msr |= MSR_SPE;
4637 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4638 return 1;
4639 }
4640
4641 /* Store MSR. */
4642 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4643 return 1;
4644
4645 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4646 if (sigret) {
4647 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4648 __put_user(0x44000002UL, &frame->tramp[1])) {
4649 return 1;
4650 }
4651 }
4652
4653 return 0;
4654}
4655
Andreas Färber05390242012-02-25 03:37:53 +01004656static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004657 struct target_mcontext *frame, int sig)
4658{
4659 target_ulong save_r2 = 0;
4660 target_ulong msr;
4661 target_ulong ccr;
4662
4663 int i;
4664
4665 if (!sig) {
4666 save_r2 = env->gpr[2];
4667 }
4668
4669 /* Restore general registers. */
4670 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4671 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4672 return 1;
4673 }
4674 }
4675 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4676 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4677 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4678 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4679 return 1;
4680 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4681 return 1;
4682
4683 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4684 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4685 }
4686
4687 if (!sig) {
4688 env->gpr[2] = save_r2;
4689 }
4690 /* Restore MSR. */
4691 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4692 return 1;
4693
4694 /* If doing signal return, restore the previous little-endian mode. */
4695 if (sig)
4696 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4697
4698 /* Restore Altivec registers if necessary. */
4699 if (env->insns_flags & PPC_ALTIVEC) {
4700 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004701 ppc_avr_t *avr = &env->avr[i];
4702 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004703
4704 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4705 __get_user(avr->u64[1], &vreg->u64[1])) {
4706 return 1;
4707 }
4708 }
4709 /* Set MSR_VEC in the saved MSR value to indicate that
4710 frame->mc_vregs contains valid data. */
4711 if (__get_user(env->spr[SPR_VRSAVE],
4712 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4713 return 1;
4714 }
4715
4716 /* Restore floating point registers. */
4717 if (env->insns_flags & PPC_FLOAT) {
4718 uint64_t fpscr;
4719 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4720 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4721 return 1;
4722 }
4723 }
4724 if (__get_user(fpscr, &frame->mc_fregs[32]))
4725 return 1;
4726 env->fpscr = (uint32_t) fpscr;
4727 }
4728
4729 /* Save SPE registers. The kernel only saves the high half. */
4730 if (env->insns_flags & PPC_SPE) {
4731#if defined(TARGET_PPC64)
4732 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4733 uint32_t hi;
4734
4735 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4736 return 1;
4737 }
4738 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4739 }
4740#else
4741 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4742 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4743 return 1;
4744 }
4745 }
4746#endif
4747 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4748 return 1;
4749 }
4750
4751 return 0;
4752}
4753
4754static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004755 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004756{
4757 struct target_sigframe *frame;
4758 struct target_sigcontext *sc;
4759 target_ulong frame_addr, newsp;
4760 int err = 0;
4761 int signal;
4762
4763 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4764 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4765 goto sigsegv;
4766 sc = &frame->sctx;
4767
4768 signal = current_exec_domain_sig(sig);
4769
Samuel Seaybeb526b2013-01-02 10:53:46 +00004770 err |= __put_user(ka->_sa_handler, &sc->handler);
Nathan Froydbcd49332009-05-12 19:13:18 -07004771 err |= __put_user(set->sig[0], &sc->oldmask);
4772#if defined(TARGET_PPC64)
4773 err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
4774#else
4775 err |= __put_user(set->sig[1], &sc->_unused[3]);
4776#endif
4777 err |= __put_user(h2g(&frame->mctx), &sc->regs);
4778 err |= __put_user(sig, &sc->signal);
4779
4780 /* Save user regs. */
4781 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4782
4783 /* The kernel checks for the presence of a VDSO here. We don't
4784 emulate a vdso, so use a sigreturn system call. */
4785 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4786
4787 /* Turn off all fp exceptions. */
4788 env->fpscr = 0;
4789
4790 /* Create a stack frame for the caller of the handler. */
4791 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004792 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004793
4794 if (err)
4795 goto sigsegv;
4796
4797 /* Set up registers for signal handler. */
4798 env->gpr[1] = newsp;
4799 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004800 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004801 env->nip = (target_ulong) ka->_sa_handler;
4802 /* Signal handlers are entered in big-endian mode. */
4803 env->msr &= ~MSR_LE;
4804
4805 unlock_user_struct(frame, frame_addr, 1);
4806 return;
4807
4808sigsegv:
4809 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004810 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004811 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004812}
4813
4814static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004815 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004816 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004817{
4818 struct target_rt_sigframe *rt_sf;
4819 struct target_mcontext *frame;
4820 target_ulong rt_sf_addr, newsp = 0;
4821 int i, err = 0;
4822 int signal;
4823
4824 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4825 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4826 goto sigsegv;
4827
4828 signal = current_exec_domain_sig(sig);
4829
4830 err |= copy_siginfo_to_user(&rt_sf->info, info);
4831
Aurelien Jarno60e99242010-03-29 02:12:51 +02004832 err |= __put_user(0, &rt_sf->uc.tuc_flags);
4833 err |= __put_user(0, &rt_sf->uc.tuc_link);
Nathan Froydbcd49332009-05-12 19:13:18 -07004834 err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004835 &rt_sf->uc.tuc_stack.ss_sp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004836 err |= __put_user(sas_ss_flags(env->gpr[1]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02004837 &rt_sf->uc.tuc_stack.ss_flags);
Nathan Froydbcd49332009-05-12 19:13:18 -07004838 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004839 &rt_sf->uc.tuc_stack.ss_size);
4840 err |= __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4841 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004842 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004843 err |= __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004844 }
4845
Aurelien Jarno60e99242010-03-29 02:12:51 +02004846 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004847 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4848
4849 /* The kernel checks for the presence of a VDSO here. We don't
4850 emulate a vdso, so use a sigreturn system call. */
4851 env->lr = (target_ulong) h2g(frame->tramp);
4852
4853 /* Turn off all fp exceptions. */
4854 env->fpscr = 0;
4855
4856 /* Create a stack frame for the caller of the handler. */
4857 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
4858 err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
4859
4860 if (err)
4861 goto sigsegv;
4862
4863 /* Set up registers for signal handler. */
4864 env->gpr[1] = newsp;
4865 env->gpr[3] = (target_ulong) signal;
4866 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4867 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4868 env->gpr[6] = (target_ulong) h2g(rt_sf);
4869 env->nip = (target_ulong) ka->_sa_handler;
4870 /* Signal handlers are entered in big-endian mode. */
4871 env->msr &= ~MSR_LE;
4872
4873 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4874 return;
4875
4876sigsegv:
4877 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004878 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004879 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004880
4881}
4882
Andreas Färber05390242012-02-25 03:37:53 +01004883long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004884{
4885 struct target_sigcontext *sc = NULL;
4886 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004887 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004888 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004889 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004890
4891 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4892 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4893 goto sigsegv;
4894
4895#if defined(TARGET_PPC64)
4896 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4897#else
4898 if(__get_user(set.sig[0], &sc->oldmask) ||
4899 __get_user(set.sig[1], &sc->_unused[3]))
4900 goto sigsegv;
4901#endif
4902 target_to_host_sigset_internal(&blocked, &set);
4903 sigprocmask(SIG_SETMASK, &blocked, NULL);
4904
4905 if (__get_user(sr_addr, &sc->regs))
4906 goto sigsegv;
4907 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4908 goto sigsegv;
4909 if (restore_user_regs(env, sr, 1))
4910 goto sigsegv;
4911
4912 unlock_user_struct(sr, sr_addr, 1);
4913 unlock_user_struct(sc, sc_addr, 1);
4914 return -TARGET_QEMU_ESIGRETURN;
4915
4916sigsegv:
4917 unlock_user_struct(sr, sr_addr, 1);
4918 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004919 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004920 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004921 return 0;
4922}
4923
4924/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004925static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004926{
4927 struct target_mcontext *mcp;
4928 target_ulong mcp_addr;
4929 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004930 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004931
Aurelien Jarno60e99242010-03-29 02:12:51 +02004932 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004933 sizeof (set)))
4934 return 1;
4935
4936#if defined(TARGET_PPC64)
4937 fprintf (stderr, "do_setcontext: not implemented\n");
4938 return 0;
4939#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004940 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004941 return 1;
4942
4943 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4944 return 1;
4945
4946 target_to_host_sigset_internal(&blocked, &set);
4947 sigprocmask(SIG_SETMASK, &blocked, NULL);
4948 if (restore_user_regs(env, mcp, sig))
4949 goto sigsegv;
4950
4951 unlock_user_struct(mcp, mcp_addr, 1);
4952 return 0;
4953
4954sigsegv:
4955 unlock_user_struct(mcp, mcp_addr, 1);
4956 return 1;
4957#endif
4958}
4959
Andreas Färber05390242012-02-25 03:37:53 +01004960long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004961{
4962 struct target_rt_sigframe *rt_sf = NULL;
4963 target_ulong rt_sf_addr;
4964
4965 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4966 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4967 goto sigsegv;
4968
4969 if (do_setcontext(&rt_sf->uc, env, 1))
4970 goto sigsegv;
4971
4972 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004973 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004974 0, env->gpr[1]);
4975
4976 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4977 return -TARGET_QEMU_ESIGRETURN;
4978
4979sigsegv:
4980 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004981 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004982 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004983 return 0;
4984}
4985
Laurent Vivier492a8742009-08-03 16:12:17 +02004986#elif defined(TARGET_M68K)
4987
4988struct target_sigcontext {
4989 abi_ulong sc_mask;
4990 abi_ulong sc_usp;
4991 abi_ulong sc_d0;
4992 abi_ulong sc_d1;
4993 abi_ulong sc_a0;
4994 abi_ulong sc_a1;
4995 unsigned short sc_sr;
4996 abi_ulong sc_pc;
4997};
4998
4999struct target_sigframe
5000{
5001 abi_ulong pretcode;
5002 int sig;
5003 int code;
5004 abi_ulong psc;
5005 char retcode[8];
5006 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5007 struct target_sigcontext sc;
5008};
Laurent Vivier71811552009-08-03 16:12:18 +02005009
Anthony Liguoric227f092009-10-01 16:12:16 -05005010typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005011#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005012typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005013
5014typedef struct target_fpregset {
5015 int f_fpcntl[3];
5016 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005017} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005018
5019struct target_mcontext {
5020 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005021 target_gregset_t gregs;
5022 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005023};
5024
5025#define TARGET_MCONTEXT_VERSION 2
5026
5027struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005028 abi_ulong tuc_flags;
5029 abi_ulong tuc_link;
5030 target_stack_t tuc_stack;
5031 struct target_mcontext tuc_mcontext;
5032 abi_long tuc_filler[80];
5033 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005034};
5035
5036struct target_rt_sigframe
5037{
5038 abi_ulong pretcode;
5039 int sig;
5040 abi_ulong pinfo;
5041 abi_ulong puc;
5042 char retcode[8];
5043 struct target_siginfo info;
5044 struct target_ucontext uc;
5045};
Laurent Vivier492a8742009-08-03 16:12:17 +02005046
5047static int
Andreas Färber05390242012-02-25 03:37:53 +01005048setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
5049 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005050{
5051 int err = 0;
5052
5053 err |= __put_user(mask, &sc->sc_mask);
5054 err |= __put_user(env->aregs[7], &sc->sc_usp);
5055 err |= __put_user(env->dregs[0], &sc->sc_d0);
5056 err |= __put_user(env->dregs[1], &sc->sc_d1);
5057 err |= __put_user(env->aregs[0], &sc->sc_a0);
5058 err |= __put_user(env->aregs[1], &sc->sc_a1);
5059 err |= __put_user(env->sr, &sc->sc_sr);
5060 err |= __put_user(env->pc, &sc->sc_pc);
5061
5062 return err;
5063}
5064
5065static int
Andreas Färber05390242012-02-25 03:37:53 +01005066restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005067{
5068 int err = 0;
5069 int temp;
5070
5071 err |= __get_user(env->aregs[7], &sc->sc_usp);
5072 err |= __get_user(env->dregs[1], &sc->sc_d1);
5073 err |= __get_user(env->aregs[0], &sc->sc_a0);
5074 err |= __get_user(env->aregs[1], &sc->sc_a1);
5075 err |= __get_user(env->pc, &sc->sc_pc);
5076 err |= __get_user(temp, &sc->sc_sr);
5077 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5078
5079 *pd0 = tswapl(sc->sc_d0);
5080
5081 return err;
5082}
5083
5084/*
5085 * Determine which stack to use..
5086 */
5087static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005088get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5089 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005090{
5091 unsigned long sp;
5092
5093 sp = regs->aregs[7];
5094
5095 /* This is the X/Open sanctioned signal stack switching. */
5096 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5097 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5098 }
5099
5100 return ((sp - frame_size) & -8UL);
5101}
5102
5103static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005104 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005105{
5106 struct target_sigframe *frame;
5107 abi_ulong frame_addr;
5108 abi_ulong retcode_addr;
5109 abi_ulong sc_addr;
5110 int err = 0;
5111 int i;
5112
5113 frame_addr = get_sigframe(ka, env, sizeof *frame);
5114 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5115 goto give_sigsegv;
5116
5117 err |= __put_user(sig, &frame->sig);
5118
5119 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
5120 err |= __put_user(sc_addr, &frame->psc);
5121
5122 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
5123 if (err)
5124 goto give_sigsegv;
5125
5126 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5127 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
5128 goto give_sigsegv;
5129 }
5130
5131 /* Set up to return from userspace. */
5132
5133 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5134 err |= __put_user(retcode_addr, &frame->pretcode);
5135
5136 /* moveq #,d0; trap #0 */
5137
5138 err |= __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
5139 (long *)(frame->retcode));
5140
5141 if (err)
5142 goto give_sigsegv;
5143
5144 /* Set up to return from userspace */
5145
5146 env->aregs[7] = frame_addr;
5147 env->pc = ka->_sa_handler;
5148
5149 unlock_user_struct(frame, frame_addr, 1);
5150 return;
5151
5152give_sigsegv:
5153 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005154 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005155}
5156
Laurent Vivier71811552009-08-03 16:12:18 +02005157static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005158 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005159{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005160 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005161 int err;
5162
Aurelien Jarno60e99242010-03-29 02:12:51 +02005163 err = __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005164 err |= __put_user(env->dregs[0], &gregs[0]);
5165 err |= __put_user(env->dregs[1], &gregs[1]);
5166 err |= __put_user(env->dregs[2], &gregs[2]);
5167 err |= __put_user(env->dregs[3], &gregs[3]);
5168 err |= __put_user(env->dregs[4], &gregs[4]);
5169 err |= __put_user(env->dregs[5], &gregs[5]);
5170 err |= __put_user(env->dregs[6], &gregs[6]);
5171 err |= __put_user(env->dregs[7], &gregs[7]);
5172 err |= __put_user(env->aregs[0], &gregs[8]);
5173 err |= __put_user(env->aregs[1], &gregs[9]);
5174 err |= __put_user(env->aregs[2], &gregs[10]);
5175 err |= __put_user(env->aregs[3], &gregs[11]);
5176 err |= __put_user(env->aregs[4], &gregs[12]);
5177 err |= __put_user(env->aregs[5], &gregs[13]);
5178 err |= __put_user(env->aregs[6], &gregs[14]);
5179 err |= __put_user(env->aregs[7], &gregs[15]);
5180 err |= __put_user(env->pc, &gregs[16]);
5181 err |= __put_user(env->sr, &gregs[17]);
5182
5183 return err;
5184}
5185
Andreas Färber05390242012-02-25 03:37:53 +01005186static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005187 struct target_ucontext *uc,
5188 int *pd0)
5189{
5190 int temp;
5191 int err;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005192 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005193
Aurelien Jarno60e99242010-03-29 02:12:51 +02005194 err = __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005195 if (temp != TARGET_MCONTEXT_VERSION)
5196 goto badframe;
5197
5198 /* restore passed registers */
5199 err |= __get_user(env->dregs[0], &gregs[0]);
5200 err |= __get_user(env->dregs[1], &gregs[1]);
5201 err |= __get_user(env->dregs[2], &gregs[2]);
5202 err |= __get_user(env->dregs[3], &gregs[3]);
5203 err |= __get_user(env->dregs[4], &gregs[4]);
5204 err |= __get_user(env->dregs[5], &gregs[5]);
5205 err |= __get_user(env->dregs[6], &gregs[6]);
5206 err |= __get_user(env->dregs[7], &gregs[7]);
5207 err |= __get_user(env->aregs[0], &gregs[8]);
5208 err |= __get_user(env->aregs[1], &gregs[9]);
5209 err |= __get_user(env->aregs[2], &gregs[10]);
5210 err |= __get_user(env->aregs[3], &gregs[11]);
5211 err |= __get_user(env->aregs[4], &gregs[12]);
5212 err |= __get_user(env->aregs[5], &gregs[13]);
5213 err |= __get_user(env->aregs[6], &gregs[14]);
5214 err |= __get_user(env->aregs[7], &gregs[15]);
5215 err |= __get_user(env->pc, &gregs[16]);
5216 err |= __get_user(temp, &gregs[17]);
5217 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5218
5219 *pd0 = env->dregs[0];
5220 return err;
5221
5222badframe:
5223 return 1;
5224}
5225
Laurent Vivier492a8742009-08-03 16:12:17 +02005226static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005227 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005228 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005229{
Laurent Vivier71811552009-08-03 16:12:18 +02005230 struct target_rt_sigframe *frame;
5231 abi_ulong frame_addr;
5232 abi_ulong retcode_addr;
5233 abi_ulong info_addr;
5234 abi_ulong uc_addr;
5235 int err = 0;
5236 int i;
5237
5238 frame_addr = get_sigframe(ka, env, sizeof *frame);
5239 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5240 goto give_sigsegv;
5241
5242 err |= __put_user(sig, &frame->sig);
5243
5244 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
5245 err |= __put_user(info_addr, &frame->pinfo);
5246
5247 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
5248 err |= __put_user(uc_addr, &frame->puc);
5249
5250 err |= copy_siginfo_to_user(&frame->info, info);
5251
5252 /* Create the ucontext */
5253
Aurelien Jarno60e99242010-03-29 02:12:51 +02005254 err |= __put_user(0, &frame->uc.tuc_flags);
5255 err |= __put_user(0, &frame->uc.tuc_link);
Laurent Vivier71811552009-08-03 16:12:18 +02005256 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005257 &frame->uc.tuc_stack.ss_sp);
Laurent Vivier71811552009-08-03 16:12:18 +02005258 err |= __put_user(sas_ss_flags(env->aregs[7]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005259 &frame->uc.tuc_stack.ss_flags);
Laurent Vivier71811552009-08-03 16:12:18 +02005260 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005261 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005262 err |= target_rt_setup_ucontext(&frame->uc, env);
5263
5264 if (err)
5265 goto give_sigsegv;
5266
5267 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005268 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005269 goto give_sigsegv;
5270 }
5271
5272 /* Set up to return from userspace. */
5273
5274 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5275 err |= __put_user(retcode_addr, &frame->pretcode);
5276
5277 /* moveq #,d0; notb d0; trap #0 */
5278
5279 err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5280 (long *)(frame->retcode + 0));
5281 err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
5282
5283 if (err)
5284 goto give_sigsegv;
5285
5286 /* Set up to return from userspace */
5287
5288 env->aregs[7] = frame_addr;
5289 env->pc = ka->_sa_handler;
5290
5291 unlock_user_struct(frame, frame_addr, 1);
5292 return;
5293
5294give_sigsegv:
5295 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005296 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005297}
5298
Andreas Färber05390242012-02-25 03:37:53 +01005299long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005300{
5301 struct target_sigframe *frame;
5302 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005303 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005304 sigset_t set;
5305 int d0, i;
5306
5307 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5308 goto badframe;
5309
5310 /* set blocked signals */
5311
5312 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
5313 goto badframe;
5314
5315 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5316 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
5317 goto badframe;
5318 }
5319
5320 target_to_host_sigset_internal(&set, &target_set);
5321 sigprocmask(SIG_SETMASK, &set, NULL);
5322
5323 /* restore registers */
5324
5325 if (restore_sigcontext(env, &frame->sc, &d0))
5326 goto badframe;
5327
5328 unlock_user_struct(frame, frame_addr, 0);
5329 return d0;
5330
5331badframe:
5332 unlock_user_struct(frame, frame_addr, 0);
5333 force_sig(TARGET_SIGSEGV);
5334 return 0;
5335}
5336
Andreas Färber05390242012-02-25 03:37:53 +01005337long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005338{
Laurent Vivier71811552009-08-03 16:12:18 +02005339 struct target_rt_sigframe *frame;
5340 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005341 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005342 sigset_t set;
5343 int d0;
5344
5345 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5346 goto badframe;
5347
5348 target_to_host_sigset_internal(&set, &target_set);
5349 sigprocmask(SIG_SETMASK, &set, NULL);
5350
5351 /* restore registers */
5352
5353 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5354 goto badframe;
5355
5356 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005357 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005358 0, get_sp_from_cpustate(env)) == -EFAULT)
5359 goto badframe;
5360
5361 unlock_user_struct(frame, frame_addr, 0);
5362 return d0;
5363
5364badframe:
5365 unlock_user_struct(frame, frame_addr, 0);
5366 force_sig(TARGET_SIGSEGV);
5367 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005368}
5369
Richard Henderson6049f4f2009-12-27 18:30:03 -08005370#elif defined(TARGET_ALPHA)
5371
5372struct target_sigcontext {
5373 abi_long sc_onstack;
5374 abi_long sc_mask;
5375 abi_long sc_pc;
5376 abi_long sc_ps;
5377 abi_long sc_regs[32];
5378 abi_long sc_ownedfp;
5379 abi_long sc_fpregs[32];
5380 abi_ulong sc_fpcr;
5381 abi_ulong sc_fp_control;
5382 abi_ulong sc_reserved1;
5383 abi_ulong sc_reserved2;
5384 abi_ulong sc_ssize;
5385 abi_ulong sc_sbase;
5386 abi_ulong sc_traparg_a0;
5387 abi_ulong sc_traparg_a1;
5388 abi_ulong sc_traparg_a2;
5389 abi_ulong sc_fp_trap_pc;
5390 abi_ulong sc_fp_trigger_sum;
5391 abi_ulong sc_fp_trigger_inst;
5392};
5393
5394struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005395 abi_ulong tuc_flags;
5396 abi_ulong tuc_link;
5397 abi_ulong tuc_osf_sigmask;
5398 target_stack_t tuc_stack;
5399 struct target_sigcontext tuc_mcontext;
5400 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005401};
5402
5403struct target_sigframe {
5404 struct target_sigcontext sc;
5405 unsigned int retcode[3];
5406};
5407
5408struct target_rt_sigframe {
5409 target_siginfo_t info;
5410 struct target_ucontext uc;
5411 unsigned int retcode[3];
5412};
5413
5414#define INSN_MOV_R30_R16 0x47fe0410
5415#define INSN_LDI_R0 0x201f0000
5416#define INSN_CALLSYS 0x00000083
5417
Andreas Färber05390242012-02-25 03:37:53 +01005418static int setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005419 abi_ulong frame_addr, target_sigset_t *set)
5420{
5421 int i, err = 0;
5422
5423 err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5424 err |= __put_user(set->sig[0], &sc->sc_mask);
5425 err |= __put_user(env->pc, &sc->sc_pc);
5426 err |= __put_user(8, &sc->sc_ps);
5427
5428 for (i = 0; i < 31; ++i) {
5429 err |= __put_user(env->ir[i], &sc->sc_regs[i]);
5430 }
5431 err |= __put_user(0, &sc->sc_regs[31]);
5432
5433 for (i = 0; i < 31; ++i) {
5434 err |= __put_user(env->fir[i], &sc->sc_fpregs[i]);
5435 }
5436 err |= __put_user(0, &sc->sc_fpregs[31]);
5437 err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
5438
5439 err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5440 err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5441 err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */
5442
5443 return err;
5444}
5445
Andreas Färber05390242012-02-25 03:37:53 +01005446static int restore_sigcontext(CPUAlphaState *env,
5447 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005448{
5449 uint64_t fpcr;
5450 int i, err = 0;
5451
5452 err |= __get_user(env->pc, &sc->sc_pc);
5453
5454 for (i = 0; i < 31; ++i) {
5455 err |= __get_user(env->ir[i], &sc->sc_regs[i]);
5456 }
5457 for (i = 0; i < 31; ++i) {
5458 err |= __get_user(env->fir[i], &sc->sc_fpregs[i]);
5459 }
5460
5461 err |= __get_user(fpcr, &sc->sc_fpcr);
5462 cpu_alpha_store_fpcr(env, fpcr);
5463
5464 return err;
5465}
5466
5467static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005468 CPUAlphaState *env,
5469 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005470{
5471 abi_ulong sp = env->ir[IR_SP];
5472
5473 /* This is the X/Open sanctioned signal stack switching. */
5474 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5475 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5476 }
5477 return (sp - framesize) & -32;
5478}
5479
5480static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005481 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005482{
5483 abi_ulong frame_addr, r26;
5484 struct target_sigframe *frame;
5485 int err = 0;
5486
5487 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5488 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5489 goto give_sigsegv;
5490 }
5491
5492 err |= setup_sigcontext(&frame->sc, env, frame_addr, set);
5493
5494 if (ka->sa_restorer) {
5495 r26 = ka->sa_restorer;
5496 } else {
5497 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5498 err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5499 &frame->retcode[1]);
5500 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5501 /* imb() */
5502 r26 = frame_addr;
5503 }
5504
5505 unlock_user_struct(frame, frame_addr, 1);
5506
5507 if (err) {
5508 give_sigsegv:
5509 if (sig == TARGET_SIGSEGV) {
5510 ka->_sa_handler = TARGET_SIG_DFL;
5511 }
5512 force_sig(TARGET_SIGSEGV);
5513 }
5514
5515 env->ir[IR_RA] = r26;
5516 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5517 env->ir[IR_A0] = sig;
5518 env->ir[IR_A1] = 0;
5519 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5520 env->ir[IR_SP] = frame_addr;
5521}
5522
5523static void setup_rt_frame(int sig, struct target_sigaction *ka,
5524 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005525 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005526{
5527 abi_ulong frame_addr, r26;
5528 struct target_rt_sigframe *frame;
5529 int i, err = 0;
5530
5531 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5532 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5533 goto give_sigsegv;
5534 }
5535
5536 err |= copy_siginfo_to_user(&frame->info, info);
5537
Aurelien Jarno60e99242010-03-29 02:12:51 +02005538 err |= __put_user(0, &frame->uc.tuc_flags);
5539 err |= __put_user(0, &frame->uc.tuc_link);
5540 err |= __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005541 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005542 &frame->uc.tuc_stack.ss_sp);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005543 err |= __put_user(sas_ss_flags(env->ir[IR_SP]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005544 &frame->uc.tuc_stack.ss_flags);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005545 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005546 &frame->uc.tuc_stack.ss_size);
5547 err |= setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005548 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005549 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005550 }
5551
5552 if (ka->sa_restorer) {
5553 r26 = ka->sa_restorer;
5554 } else {
5555 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5556 err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5557 &frame->retcode[1]);
5558 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5559 /* imb(); */
5560 r26 = frame_addr;
5561 }
5562
5563 if (err) {
5564 give_sigsegv:
5565 if (sig == TARGET_SIGSEGV) {
5566 ka->_sa_handler = TARGET_SIG_DFL;
5567 }
5568 force_sig(TARGET_SIGSEGV);
5569 }
5570
5571 env->ir[IR_RA] = r26;
5572 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5573 env->ir[IR_A0] = sig;
5574 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5575 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5576 env->ir[IR_SP] = frame_addr;
5577}
5578
Andreas Färber05390242012-02-25 03:37:53 +01005579long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005580{
5581 struct target_sigcontext *sc;
5582 abi_ulong sc_addr = env->ir[IR_A0];
5583 target_sigset_t target_set;
5584 sigset_t set;
5585
5586 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5587 goto badframe;
5588 }
5589
5590 target_sigemptyset(&target_set);
5591 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
5592 goto badframe;
5593 }
5594
5595 target_to_host_sigset_internal(&set, &target_set);
5596 sigprocmask(SIG_SETMASK, &set, NULL);
5597
5598 if (restore_sigcontext(env, sc)) {
5599 goto badframe;
5600 }
5601 unlock_user_struct(sc, sc_addr, 0);
5602 return env->ir[IR_V0];
5603
5604 badframe:
5605 unlock_user_struct(sc, sc_addr, 0);
5606 force_sig(TARGET_SIGSEGV);
5607}
5608
Andreas Färber05390242012-02-25 03:37:53 +01005609long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005610{
5611 abi_ulong frame_addr = env->ir[IR_A0];
5612 struct target_rt_sigframe *frame;
5613 sigset_t set;
5614
5615 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5616 goto badframe;
5617 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005618 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005619 sigprocmask(SIG_SETMASK, &set, NULL);
5620
Aurelien Jarno60e99242010-03-29 02:12:51 +02005621 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005622 goto badframe;
5623 }
5624 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005625 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005626 0, env->ir[IR_SP]) == -EFAULT) {
5627 goto badframe;
5628 }
5629
5630 unlock_user_struct(frame, frame_addr, 0);
5631 return env->ir[IR_V0];
5632
5633
5634 badframe:
5635 unlock_user_struct(frame, frame_addr, 0);
5636 force_sig(TARGET_SIGSEGV);
5637}
5638
bellardb346ff42003-06-15 20:05:50 +00005639#else
5640
pbrook624f7972008-05-31 16:11:38 +00005641static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005642 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005643{
5644 fprintf(stderr, "setup_frame: not implemented\n");
5645}
5646
pbrook624f7972008-05-31 16:11:38 +00005647static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005648 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005649 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005650{
5651 fprintf(stderr, "setup_rt_frame: not implemented\n");
5652}
5653
Andreas Färber9349b4f2012-03-14 01:38:32 +01005654long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005655{
5656 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005657 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005658}
5659
Andreas Färber9349b4f2012-03-14 01:38:32 +01005660long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005661{
5662 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005663 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005664}
5665
bellard66fb9762003-03-23 01:06:05 +00005666#endif
5667
Andreas Färber9349b4f2012-03-14 01:38:32 +01005668void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005669{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005670 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005671 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005672 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005673 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005674 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005675 struct emulated_sigtable *k;
5676 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005677 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00005678 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00005679
pbrook624f7972008-05-31 16:11:38 +00005680 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005681 return;
5682
pbrook624f7972008-05-31 16:11:38 +00005683 /* FIXME: This is not threadsafe. */
5684 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005685 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5686 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005687 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005688 k++;
bellard31e31b82003-02-18 22:55:36 +00005689 }
5690 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005691 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005692 return;
bellard66fb9762003-03-23 01:06:05 +00005693
bellard31e31b82003-02-18 22:55:36 +00005694 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005695#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005696 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005697#endif
5698 /* dequeue signal */
5699 q = k->first;
5700 k->first = q->next;
5701 if (!k->first)
5702 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005703
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005704 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005705 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005706 sa = NULL;
5707 handler = TARGET_SIG_IGN;
5708 } else {
5709 sa = &sigact_table[sig - 1];
5710 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005711 }
bellard66fb9762003-03-23 01:06:05 +00005712
bellard66fb9762003-03-23 01:06:05 +00005713 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005714 /* default handler : ignore some signal. The other are job control or fatal */
5715 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5716 kill(getpid(),SIGSTOP);
5717 } else if (sig != TARGET_SIGCHLD &&
5718 sig != TARGET_SIGURG &&
5719 sig != TARGET_SIGWINCH &&
5720 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005721 force_sig(sig);
5722 }
5723 } else if (handler == TARGET_SIG_IGN) {
5724 /* ignore sig */
5725 } else if (handler == TARGET_SIG_ERR) {
5726 force_sig(sig);
5727 } else {
bellard9de5e442003-03-23 16:49:39 +00005728 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005729 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005730 /* SA_NODEFER indicates that the current signal should not be
5731 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005732 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005733 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005734
bellard9de5e442003-03-23 16:49:39 +00005735 /* block signals in the handler using Linux */
5736 sigprocmask(SIG_BLOCK, &set, &old_set);
5737 /* save the previous blocked signal state to restore it at the
5738 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005739 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005740
bellardbc8a22c2003-03-30 21:02:40 +00005741 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005742#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005743 {
5744 CPUX86State *env = cpu_env;
5745 if (env->eflags & VM_MASK)
5746 save_v86_state(env);
5747 }
5748#endif
bellard9de5e442003-03-23 16:49:39 +00005749 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005750#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5751 /* These targets do not have traditional signals. */
5752 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5753#else
pbrook624f7972008-05-31 16:11:38 +00005754 if (sa->sa_flags & TARGET_SA_SIGINFO)
5755 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005756 else
pbrook624f7972008-05-31 16:11:38 +00005757 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005758#endif
pbrook624f7972008-05-31 16:11:38 +00005759 if (sa->sa_flags & TARGET_SA_RESETHAND)
5760 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005761 }
bellard66fb9762003-03-23 01:06:05 +00005762 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005763 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005764}