blob: acf10328eec80a473924f96240984541fa2b3904 [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{
Andreas Färber27103422013-08-26 08:31:06 +0200777 CPUState *cs = CPU(x86_env_get_cpu(env));
778 int err = 0;
779 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000780
bellard579a97f2007-11-11 14:26:47 +0000781 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000782 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
783 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
784 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
785 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000786 err |= __put_user(env->regs[R_EDI], &sc->edi);
787 err |= __put_user(env->regs[R_ESI], &sc->esi);
788 err |= __put_user(env->regs[R_EBP], &sc->ebp);
789 err |= __put_user(env->regs[R_ESP], &sc->esp);
790 err |= __put_user(env->regs[R_EBX], &sc->ebx);
791 err |= __put_user(env->regs[R_EDX], &sc->edx);
792 err |= __put_user(env->regs[R_ECX], &sc->ecx);
793 err |= __put_user(env->regs[R_EAX], &sc->eax);
Andreas Färber27103422013-08-26 08:31:06 +0200794 err |= __put_user(cs->exception_index, &sc->trapno);
bellard66099dd2003-05-08 15:34:02 +0000795 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000796 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000797 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000798 err |= __put_user(env->eflags, &sc->eflags);
799 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000800 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000801
bellard28be6232007-11-11 22:23:38 +0000802 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000803 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000804 magic = 0xffff;
805 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000806 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000807
bellard66fb9762003-03-23 01:06:05 +0000808 /* non-iBCS2 extensions.. */
809 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000810 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000811 return err;
812}
813
814/*
815 * Determine which stack to use..
816 */
817
bellard579a97f2007-11-11 14:26:47 +0000818static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000819get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000820{
821 unsigned long esp;
822
823 /* Default to using normal stack */
824 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000825 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000826 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000827 if (sas_ss_flags(esp) == 0)
828 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
829 }
bellard66fb9762003-03-23 01:06:05 +0000830
831 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000832 else
bellarda52c7572003-06-21 13:14:12 +0000833 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000834 !(ka->sa_flags & TARGET_SA_RESTORER) &&
835 ka->sa_restorer) {
836 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000837 }
bellard579a97f2007-11-11 14:26:47 +0000838 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000839}
840
bellard579a97f2007-11-11 14:26:47 +0000841/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000842static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500843 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000844{
bellard579a97f2007-11-11 14:26:47 +0000845 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000846 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000847 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000848
bellard579a97f2007-11-11 14:26:47 +0000849 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000850
bellard579a97f2007-11-11 14:26:47 +0000851 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000852 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000853
thsc3b5bc82007-12-02 06:31:25 +0000854 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000855 &frame->sig);
856 if (err)
857 goto give_sigsegv;
858
bellard28be6232007-11-11 22:23:38 +0000859 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
860 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000861 if (err)
862 goto give_sigsegv;
863
bellard92319442004-06-19 16:58:13 +0000864 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
865 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
866 goto give_sigsegv;
867 }
bellard66fb9762003-03-23 01:06:05 +0000868
869 /* Set up to return from userspace. If provided, use a stub
870 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000871 if (ka->sa_flags & TARGET_SA_RESTORER) {
872 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000873 } else {
bellard775b58d2007-11-11 16:22:17 +0000874 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000875 abi_ulong retcode_addr;
876 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
877 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000878 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000879 val16 = 0xb858;
880 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000881 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000882 val16 = 0x80cd;
883 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000884 }
885
886 if (err)
887 goto give_sigsegv;
888
889 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000890 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000891 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000892
893 cpu_x86_load_seg(env, R_DS, __USER_DS);
894 cpu_x86_load_seg(env, R_ES, __USER_DS);
895 cpu_x86_load_seg(env, R_SS, __USER_DS);
896 cpu_x86_load_seg(env, R_CS, __USER_CS);
897 env->eflags &= ~TF_MASK;
898
bellard579a97f2007-11-11 14:26:47 +0000899 unlock_user_struct(frame, frame_addr, 1);
900
bellard66fb9762003-03-23 01:06:05 +0000901 return;
902
903give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000904 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000905 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000906 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000907 force_sig(TARGET_SIGSEGV /* , current */);
908}
909
bellard579a97f2007-11-11 14:26:47 +0000910/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000911static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500912 target_siginfo_t *info,
913 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000914{
bellard28be6232007-11-11 22:23:38 +0000915 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000916 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000917 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000918
bellard579a97f2007-11-11 14:26:47 +0000919 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000920
bellard579a97f2007-11-11 14:26:47 +0000921 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000922 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000923
thsc3b5bc82007-12-02 06:31:25 +0000924 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000925 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000926 addr = frame_addr + offsetof(struct rt_sigframe, info);
927 err |= __put_user(addr, &frame->pinfo);
928 addr = frame_addr + offsetof(struct rt_sigframe, uc);
929 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000930 err |= copy_siginfo_to_user(&frame->info, info);
931 if (err)
932 goto give_sigsegv;
933
934 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000935 err |= __put_user(0, &frame->uc.tuc_flags);
936 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000937 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000938 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000939 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000940 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000941 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000942 &frame->uc.tuc_stack.ss_size);
943 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000944 env, set->sig[0],
945 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000946 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000947 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000948 goto give_sigsegv;
949 }
bellard66fb9762003-03-23 01:06:05 +0000950
951 /* Set up to return from userspace. If provided, use a stub
952 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000953 if (ka->sa_flags & TARGET_SA_RESTORER) {
954 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000955 } else {
bellard775b58d2007-11-11 16:22:17 +0000956 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000957 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
958 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000959 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000960 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000961 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000962 val16 = 0x80cd;
963 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000964 }
965
966 if (err)
967 goto give_sigsegv;
968
969 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000970 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000971 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000972
973 cpu_x86_load_seg(env, R_DS, __USER_DS);
974 cpu_x86_load_seg(env, R_ES, __USER_DS);
975 cpu_x86_load_seg(env, R_SS, __USER_DS);
976 cpu_x86_load_seg(env, R_CS, __USER_CS);
977 env->eflags &= ~TF_MASK;
978
bellard579a97f2007-11-11 14:26:47 +0000979 unlock_user_struct(frame, frame_addr, 1);
980
bellard66fb9762003-03-23 01:06:05 +0000981 return;
982
983give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000984 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000985 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000986 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000987 force_sig(TARGET_SIGSEGV /* , current */);
988}
989
990static int
991restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
992{
993 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000994 abi_ulong fpstate_addr;
995 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000996
bellard28be6232007-11-11 22:23:38 +0000997 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
998 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
999 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1000 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001001
bellard28be6232007-11-11 22:23:38 +00001002 env->regs[R_EDI] = tswapl(sc->edi);
1003 env->regs[R_ESI] = tswapl(sc->esi);
1004 env->regs[R_EBP] = tswapl(sc->ebp);
1005 env->regs[R_ESP] = tswapl(sc->esp);
1006 env->regs[R_EBX] = tswapl(sc->ebx);
1007 env->regs[R_EDX] = tswapl(sc->edx);
1008 env->regs[R_ECX] = tswapl(sc->ecx);
1009 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001010
Mike McCormack9a826d72011-06-01 15:14:37 +09001011 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1012 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001013
bellard28be6232007-11-11 22:23:38 +00001014 tmpflags = tswapl(sc->eflags);
1015 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1016 // regs->orig_eax = -1; /* disable syscall checks */
1017
1018 fpstate_addr = tswapl(sc->fpstate);
1019 if (fpstate_addr != 0) {
1020 if (!access_ok(VERIFY_READ, fpstate_addr,
1021 sizeof(struct target_fpstate)))
1022 goto badframe;
1023 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001024 }
1025
bellard28be6232007-11-11 22:23:38 +00001026 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001027 return err;
bellard66fb9762003-03-23 01:06:05 +00001028badframe:
1029 return 1;
bellard66fb9762003-03-23 01:06:05 +00001030}
1031
1032long do_sigreturn(CPUX86State *env)
1033{
bellard579a97f2007-11-11 14:26:47 +00001034 struct sigframe *frame;
1035 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001036 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001037 sigset_t set;
1038 int eax, i;
1039
bellard447db212003-05-10 15:10:36 +00001040#if defined(DEBUG_SIGNAL)
1041 fprintf(stderr, "do_sigreturn\n");
1042#endif
bellard579a97f2007-11-11 14:26:47 +00001043 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1044 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001045 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +00001046 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
1047 goto badframe;
1048 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1049 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
1050 goto badframe;
1051 }
bellard66fb9762003-03-23 01:06:05 +00001052
bellard92319442004-06-19 16:58:13 +00001053 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +00001054 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001055
bellard66fb9762003-03-23 01:06:05 +00001056 /* restore registers */
1057 if (restore_sigcontext(env, &frame->sc, &eax))
1058 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001059 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001060 return eax;
1061
1062badframe:
bellard579a97f2007-11-11 14:26:47 +00001063 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001064 force_sig(TARGET_SIGSEGV);
1065 return 0;
1066}
1067
1068long do_rt_sigreturn(CPUX86State *env)
1069{
bellard28be6232007-11-11 22:23:38 +00001070 abi_ulong frame_addr;
1071 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001072 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001073 int eax;
1074
bellard28be6232007-11-11 22:23:38 +00001075 frame_addr = env->regs[R_ESP] - 4;
1076 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1077 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001078 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +00001079 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001080
bellardb8076a72005-04-07 22:20:31 +00001081 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001082 goto badframe;
1083
bellard28be6232007-11-11 22:23:38 +00001084 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1085 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001086 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001087
bellard28be6232007-11-11 22:23:38 +00001088 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001089 return eax;
1090
1091badframe:
bellard28be6232007-11-11 22:23:38 +00001092 unlock_user_struct(frame, frame_addr, 0);
1093 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001094 return 0;
1095}
1096
Andreas Schwab1744aea2013-09-03 20:12:16 +01001097#elif defined(TARGET_AARCH64)
1098
1099struct target_sigcontext {
1100 uint64_t fault_address;
1101 /* AArch64 registers */
1102 uint64_t regs[31];
1103 uint64_t sp;
1104 uint64_t pc;
1105 uint64_t pstate;
1106 /* 4K reserved for FP/SIMD state and future expansion */
1107 char __reserved[4096] __attribute__((__aligned__(16)));
1108};
1109
1110struct target_ucontext {
1111 abi_ulong tuc_flags;
1112 abi_ulong tuc_link;
1113 target_stack_t tuc_stack;
1114 target_sigset_t tuc_sigmask;
1115 /* glibc uses a 1024-bit sigset_t */
1116 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1117 /* last for future expansion */
1118 struct target_sigcontext tuc_mcontext;
1119};
1120
1121/*
1122 * Header to be used at the beginning of structures extending the user
1123 * context. Such structures must be placed after the rt_sigframe on the stack
1124 * and be 16-byte aligned. The last structure must be a dummy one with the
1125 * magic and size set to 0.
1126 */
1127struct target_aarch64_ctx {
1128 uint32_t magic;
1129 uint32_t size;
1130};
1131
1132#define TARGET_FPSIMD_MAGIC 0x46508001
1133
1134struct target_fpsimd_context {
1135 struct target_aarch64_ctx head;
1136 uint32_t fpsr;
1137 uint32_t fpcr;
1138 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1139};
1140
1141/*
1142 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1143 * user space as it will change with the addition of new context. User space
1144 * should check the magic/size information.
1145 */
1146struct target_aux_context {
1147 struct target_fpsimd_context fpsimd;
1148 /* additional context to be added before "end" */
1149 struct target_aarch64_ctx end;
1150};
1151
1152struct target_rt_sigframe {
1153 struct target_siginfo info;
1154 struct target_ucontext uc;
1155 uint64_t fp;
1156 uint64_t lr;
1157 uint32_t tramp[2];
1158};
1159
1160static int target_setup_sigframe(struct target_rt_sigframe *sf,
1161 CPUARMState *env, target_sigset_t *set)
1162{
1163 int i;
1164 struct target_aux_context *aux =
1165 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1166
1167 /* set up the stack frame for unwinding */
1168 __put_user(env->xregs[29], &sf->fp);
1169 __put_user(env->xregs[30], &sf->lr);
1170
1171 for (i = 0; i < 31; i++) {
1172 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1173 }
1174 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1175 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001176 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001177
1178 __put_user(/*current->thread.fault_address*/ 0,
1179 &sf->uc.tuc_mcontext.fault_address);
1180
1181 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1182 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1183 }
1184
1185 for (i = 0; i < 32; i++) {
1186#ifdef TARGET_WORDS_BIGENDIAN
1187 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1188 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1189#else
1190 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1191 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1192#endif
1193 }
Will Newtone0ee1382014-01-04 22:15:48 +00001194 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1195 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001196 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1197 __put_user(sizeof(struct target_fpsimd_context),
1198 &aux->fpsimd.head.size);
1199
1200 /* set the "end" magic */
1201 __put_user(0, &aux->end.magic);
1202 __put_user(0, &aux->end.size);
1203
1204 return 0;
1205}
1206
1207static int target_restore_sigframe(CPUARMState *env,
1208 struct target_rt_sigframe *sf)
1209{
1210 sigset_t set;
1211 int i;
1212 struct target_aux_context *aux =
1213 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001214 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001215 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001216
1217 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
1218 sigprocmask(SIG_SETMASK, &set, NULL);
1219
1220 for (i = 0; i < 31; i++) {
1221 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1222 }
1223
1224 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1225 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001226 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1227 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001228
1229 __get_user(magic, &aux->fpsimd.head.magic);
1230 __get_user(size, &aux->fpsimd.head.size);
1231
1232 if (magic != TARGET_FPSIMD_MAGIC
1233 || size != sizeof(struct target_fpsimd_context)) {
1234 return 1;
1235 }
1236
Peter Maydell4cf23482014-03-02 19:36:38 +00001237 for (i = 0; i < 32; i++) {
1238#ifdef TARGET_WORDS_BIGENDIAN
1239 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1240 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1241#else
1242 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1243 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1244#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001245 }
Will Newtone0ee1382014-01-04 22:15:48 +00001246 __get_user(fpsr, &aux->fpsimd.fpsr);
1247 vfp_set_fpsr(env, fpsr);
1248 __get_user(fpcr, &aux->fpsimd.fpcr);
1249 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001250
1251 return 0;
1252}
1253
1254static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1255{
1256 abi_ulong sp;
1257
1258 sp = env->xregs[31];
1259
1260 /*
1261 * This is the X/Open sanctioned signal stack switching.
1262 */
1263 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1264 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1265 }
1266
1267 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1268
1269 return sp;
1270}
1271
1272static void target_setup_frame(int usig, struct target_sigaction *ka,
1273 target_siginfo_t *info, target_sigset_t *set,
1274 CPUARMState *env)
1275{
1276 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001277 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001278
1279 frame_addr = get_sigframe(ka, env);
1280 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1281 goto give_sigsegv;
1282 }
1283
1284 __put_user(0, &frame->uc.tuc_flags);
1285 __put_user(0, &frame->uc.tuc_link);
1286
1287 __put_user(target_sigaltstack_used.ss_sp,
1288 &frame->uc.tuc_stack.ss_sp);
1289 __put_user(sas_ss_flags(env->xregs[31]),
1290 &frame->uc.tuc_stack.ss_flags);
1291 __put_user(target_sigaltstack_used.ss_size,
1292 &frame->uc.tuc_stack.ss_size);
1293 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001294 if (ka->sa_flags & TARGET_SA_RESTORER) {
1295 return_addr = ka->sa_restorer;
1296 } else {
1297 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1298 __put_user(0xd2801168, &frame->tramp[0]);
1299 __put_user(0xd4000001, &frame->tramp[1]);
1300 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1301 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001302 env->xregs[0] = usig;
1303 env->xregs[31] = frame_addr;
1304 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1305 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001306 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001307 if (info) {
1308 if (copy_siginfo_to_user(&frame->info, info)) {
1309 goto give_sigsegv;
1310 }
1311 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1312 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1313 }
1314
1315 unlock_user_struct(frame, frame_addr, 1);
1316 return;
1317
1318 give_sigsegv:
1319 unlock_user_struct(frame, frame_addr, 1);
1320 force_sig(TARGET_SIGSEGV);
1321}
1322
1323static void setup_rt_frame(int sig, struct target_sigaction *ka,
1324 target_siginfo_t *info, target_sigset_t *set,
1325 CPUARMState *env)
1326{
1327 target_setup_frame(sig, ka, info, set, env);
1328}
1329
1330static void setup_frame(int sig, struct target_sigaction *ka,
1331 target_sigset_t *set, CPUARMState *env)
1332{
1333 target_setup_frame(sig, ka, 0, set, env);
1334}
1335
1336long do_rt_sigreturn(CPUARMState *env)
1337{
1338 struct target_rt_sigframe *frame;
1339 abi_ulong frame_addr = env->xregs[31];
1340
1341 if (frame_addr & 15) {
1342 goto badframe;
1343 }
1344
1345 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1346 goto badframe;
1347 }
1348
1349 if (target_restore_sigframe(env, frame)) {
1350 goto badframe;
1351 }
1352
1353 if (do_sigaltstack(frame_addr +
1354 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1355 0, get_sp_from_cpustate(env)) == -EFAULT) {
1356 goto badframe;
1357 }
1358
1359 unlock_user_struct(frame, frame_addr, 0);
1360 return env->xregs[0];
1361
1362 badframe:
1363 unlock_user_struct(frame, frame_addr, 0);
1364 force_sig(TARGET_SIGSEGV);
1365 return 0;
1366}
1367
1368long do_sigreturn(CPUARMState *env)
1369{
1370 return do_rt_sigreturn(env);
1371}
1372
bellard43fff232003-07-09 19:31:39 +00001373#elif defined(TARGET_ARM)
1374
1375struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001376 abi_ulong trap_no;
1377 abi_ulong error_code;
1378 abi_ulong oldmask;
1379 abi_ulong arm_r0;
1380 abi_ulong arm_r1;
1381 abi_ulong arm_r2;
1382 abi_ulong arm_r3;
1383 abi_ulong arm_r4;
1384 abi_ulong arm_r5;
1385 abi_ulong arm_r6;
1386 abi_ulong arm_r7;
1387 abi_ulong arm_r8;
1388 abi_ulong arm_r9;
1389 abi_ulong arm_r10;
1390 abi_ulong arm_fp;
1391 abi_ulong arm_ip;
1392 abi_ulong arm_sp;
1393 abi_ulong arm_lr;
1394 abi_ulong arm_pc;
1395 abi_ulong arm_cpsr;
1396 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001397};
1398
pbrooka745ec62008-05-06 15:36:17 +00001399struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001400 abi_ulong tuc_flags;
1401 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001402 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001403 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001404 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001405};
1406
pbrooka745ec62008-05-06 15:36:17 +00001407struct target_ucontext_v2 {
1408 abi_ulong tuc_flags;
1409 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001410 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001411 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001412 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001413 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001414 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1415};
1416
Peter Maydell0d871bd2010-11-24 15:20:05 +00001417struct target_user_vfp {
1418 uint64_t fpregs[32];
1419 abi_ulong fpscr;
1420};
1421
1422struct target_user_vfp_exc {
1423 abi_ulong fpexc;
1424 abi_ulong fpinst;
1425 abi_ulong fpinst2;
1426};
1427
1428struct target_vfp_sigframe {
1429 abi_ulong magic;
1430 abi_ulong size;
1431 struct target_user_vfp ufp;
1432 struct target_user_vfp_exc ufp_exc;
1433} __attribute__((__aligned__(8)));
1434
Peter Maydell08e11252010-11-24 15:20:07 +00001435struct target_iwmmxt_sigframe {
1436 abi_ulong magic;
1437 abi_ulong size;
1438 uint64_t regs[16];
1439 /* Note that not all the coprocessor control registers are stored here */
1440 uint32_t wcssf;
1441 uint32_t wcasf;
1442 uint32_t wcgr0;
1443 uint32_t wcgr1;
1444 uint32_t wcgr2;
1445 uint32_t wcgr3;
1446} __attribute__((__aligned__(8)));
1447
Peter Maydell0d871bd2010-11-24 15:20:05 +00001448#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001449#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001450
pbrooka8c33202008-05-07 23:22:46 +00001451struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001452{
1453 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001454 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1455 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001456};
1457
pbrooka8c33202008-05-07 23:22:46 +00001458struct sigframe_v2
1459{
1460 struct target_ucontext_v2 uc;
1461 abi_ulong retcode;
1462};
1463
pbrooka745ec62008-05-06 15:36:17 +00001464struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001465{
bellardf8b0aa22007-11-11 23:03:42 +00001466 abi_ulong pinfo;
1467 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001468 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001469 struct target_ucontext_v1 uc;
1470 abi_ulong retcode;
1471};
1472
1473struct rt_sigframe_v2
1474{
1475 struct target_siginfo info;
1476 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001477 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001478};
1479
1480#define TARGET_CONFIG_CPU_32 1
1481
1482/*
1483 * For ARM syscalls, we encode the syscall number into the instruction.
1484 */
1485#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1486#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1487
1488/*
1489 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1490 * need two 16-bit instructions.
1491 */
1492#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1493#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1494
blueswir1992f48a2007-10-14 16:27:31 +00001495static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001496 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1497 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1498};
1499
1500
bellard43fff232003-07-09 19:31:39 +00001501#define __get_user_error(x,p,e) __get_user(x, p)
1502
Andreas Färber05390242012-02-25 03:37:53 +01001503static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001504{
1505 return 1;
1506}
1507
pbrooka8c33202008-05-07 23:22:46 +00001508static void
bellard43fff232003-07-09 19:31:39 +00001509setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001510 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001511{
pbrooka8c33202008-05-07 23:22:46 +00001512 __put_user(env->regs[0], &sc->arm_r0);
1513 __put_user(env->regs[1], &sc->arm_r1);
1514 __put_user(env->regs[2], &sc->arm_r2);
1515 __put_user(env->regs[3], &sc->arm_r3);
1516 __put_user(env->regs[4], &sc->arm_r4);
1517 __put_user(env->regs[5], &sc->arm_r5);
1518 __put_user(env->regs[6], &sc->arm_r6);
1519 __put_user(env->regs[7], &sc->arm_r7);
1520 __put_user(env->regs[8], &sc->arm_r8);
1521 __put_user(env->regs[9], &sc->arm_r9);
1522 __put_user(env->regs[10], &sc->arm_r10);
1523 __put_user(env->regs[11], &sc->arm_fp);
1524 __put_user(env->regs[12], &sc->arm_ip);
1525 __put_user(env->regs[13], &sc->arm_sp);
1526 __put_user(env->regs[14], &sc->arm_lr);
1527 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001528#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001529 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001530#endif
1531
pbrooka8c33202008-05-07 23:22:46 +00001532 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1533 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1534 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1535 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001536}
1537
bellard579a97f2007-11-11 14:26:47 +00001538static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001539get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001540{
1541 unsigned long sp = regs->regs[13];
1542
bellard43fff232003-07-09 19:31:39 +00001543 /*
1544 * This is the X/Open sanctioned signal stack switching.
1545 */
pbrook624f7972008-05-31 16:11:38 +00001546 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001547 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001548 /*
1549 * ATPCS B01 mandates 8-byte alignment
1550 */
bellard579a97f2007-11-11 14:26:47 +00001551 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001552}
1553
1554static int
Andreas Färber05390242012-02-25 03:37:53 +01001555setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001556 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001557{
pbrook624f7972008-05-31 16:11:38 +00001558 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001559 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001560 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001561 uint32_t cpsr = cpsr_read(env);
1562
1563 cpsr &= ~CPSR_IT;
1564 if (thumb) {
1565 cpsr |= CPSR_T;
1566 } else {
1567 cpsr &= ~CPSR_T;
1568 }
bellard43fff232003-07-09 19:31:39 +00001569
pbrook624f7972008-05-31 16:11:38 +00001570 if (ka->sa_flags & TARGET_SA_RESTORER) {
1571 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001572 } else {
1573 unsigned int idx = thumb;
1574
pbrook624f7972008-05-31 16:11:38 +00001575 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001576 idx += 2;
1577
1578 if (__put_user(retcodes[idx], rc))
1579 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001580
bellardf8b0aa22007-11-11 23:03:42 +00001581 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001582 }
1583
1584 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001585 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001586 env->regs[14] = retcode;
1587 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001588 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001589
1590 return 0;
1591}
1592
Andreas Färber05390242012-02-25 03:37:53 +01001593static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001594{
1595 int i;
1596 struct target_vfp_sigframe *vfpframe;
1597 vfpframe = (struct target_vfp_sigframe *)regspace;
1598 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1599 __put_user(sizeof(*vfpframe), &vfpframe->size);
1600 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001601 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001602 }
1603 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1604 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1605 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1606 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1607 return (abi_ulong*)(vfpframe+1);
1608}
1609
Andreas Färber05390242012-02-25 03:37:53 +01001610static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1611 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001612{
1613 int i;
1614 struct target_iwmmxt_sigframe *iwmmxtframe;
1615 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1616 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1617 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1618 for (i = 0; i < 16; i++) {
1619 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1620 }
1621 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1622 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1623 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1624 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1625 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1626 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1627 return (abi_ulong*)(iwmmxtframe+1);
1628}
1629
pbrooka8c33202008-05-07 23:22:46 +00001630static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001631 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001632{
pbrooka8c33202008-05-07 23:22:46 +00001633 struct target_sigaltstack stack;
1634 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001635 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001636
1637 /* Clear all the bits of the ucontext we don't use. */
1638 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1639
1640 memset(&stack, 0, sizeof(stack));
1641 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1642 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1643 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1644 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1645
1646 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001647 /* Save coprocessor signal frame. */
1648 regspace = uc->tuc_regspace;
1649 if (arm_feature(env, ARM_FEATURE_VFP)) {
1650 regspace = setup_sigframe_v2_vfp(regspace, env);
1651 }
Peter Maydell08e11252010-11-24 15:20:07 +00001652 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1653 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1654 }
1655
Peter Maydell0d871bd2010-11-24 15:20:05 +00001656 /* Write terminating magic word */
1657 __put_user(0, regspace);
1658
pbrooka8c33202008-05-07 23:22:46 +00001659 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1660 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1661 }
1662}
1663
1664/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001665static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001666 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001667{
1668 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001669 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001670 int i;
bellard43fff232003-07-09 19:31:39 +00001671
bellard579a97f2007-11-11 14:26:47 +00001672 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1673 return;
1674
pbrooka8c33202008-05-07 23:22:46 +00001675 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001676
bellard92319442004-06-19 16:58:13 +00001677 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1678 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001679 goto end;
bellard43fff232003-07-09 19:31:39 +00001680 }
1681
pbrooka8c33202008-05-07 23:22:46 +00001682 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1683 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001684
1685end:
1686 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001687}
1688
pbrook624f7972008-05-31 16:11:38 +00001689static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001690 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001691{
1692 struct sigframe_v2 *frame;
1693 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1694
1695 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1696 return;
1697
1698 setup_sigframe_v2(&frame->uc, set, regs);
1699
1700 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1701 frame_addr + offsetof(struct sigframe_v2, retcode));
1702
1703 unlock_user_struct(frame, frame_addr, 1);
1704}
1705
pbrook624f7972008-05-31 16:11:38 +00001706static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001707 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001708{
1709 if (get_osversion() >= 0x020612) {
1710 setup_frame_v2(usig, ka, set, regs);
1711 } else {
1712 setup_frame_v1(usig, ka, set, regs);
1713 }
bellard43fff232003-07-09 19:31:39 +00001714}
1715
bellard579a97f2007-11-11 14:26:47 +00001716/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001717static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001718 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001719 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001720{
pbrooka745ec62008-05-06 15:36:17 +00001721 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001722 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001723 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001724 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001725 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001726
bellard579a97f2007-11-11 14:26:47 +00001727 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001728 return /* 1 */;
1729
pbrooka745ec62008-05-06 15:36:17 +00001730 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001731 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001732 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001733 __put_user(uc_addr, &frame->puc);
1734 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001735
1736 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001737 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001738
thsa04e1342007-09-27 13:57:58 +00001739 memset(&stack, 0, sizeof(stack));
1740 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1741 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1742 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001743 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001744
pbrooka8c33202008-05-07 23:22:46 +00001745 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001746 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001747 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001748 goto end;
bellard92319442004-06-19 16:58:13 +00001749 }
bellard43fff232003-07-09 19:31:39 +00001750
pbrooka8c33202008-05-07 23:22:46 +00001751 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1752 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001753
pbrooka8c33202008-05-07 23:22:46 +00001754 env->regs[1] = info_addr;
1755 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001756
1757end:
1758 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001759}
1760
pbrook624f7972008-05-31 16:11:38 +00001761static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001762 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001763 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001764{
1765 struct rt_sigframe_v2 *frame;
1766 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001767 abi_ulong info_addr, uc_addr;
1768
1769 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1770 return /* 1 */;
1771
1772 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1773 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001774 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001775
pbrooka8c33202008-05-07 23:22:46 +00001776 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001777
pbrooka8c33202008-05-07 23:22:46 +00001778 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1779 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001780
pbrooka8c33202008-05-07 23:22:46 +00001781 env->regs[1] = info_addr;
1782 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001783
bellard579a97f2007-11-11 14:26:47 +00001784 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001785}
1786
pbrook624f7972008-05-31 16:11:38 +00001787static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001788 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001789 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001790{
1791 if (get_osversion() >= 0x020612) {
1792 setup_rt_frame_v2(usig, ka, info, set, env);
1793 } else {
1794 setup_rt_frame_v1(usig, ka, info, set, env);
1795 }
1796}
1797
bellard43fff232003-07-09 19:31:39 +00001798static int
Andreas Färber05390242012-02-25 03:37:53 +01001799restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001800{
1801 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001802 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001803
1804 __get_user_error(env->regs[0], &sc->arm_r0, err);
1805 __get_user_error(env->regs[1], &sc->arm_r1, err);
1806 __get_user_error(env->regs[2], &sc->arm_r2, err);
1807 __get_user_error(env->regs[3], &sc->arm_r3, err);
1808 __get_user_error(env->regs[4], &sc->arm_r4, err);
1809 __get_user_error(env->regs[5], &sc->arm_r5, err);
1810 __get_user_error(env->regs[6], &sc->arm_r6, err);
1811 __get_user_error(env->regs[7], &sc->arm_r7, err);
1812 __get_user_error(env->regs[8], &sc->arm_r8, err);
1813 __get_user_error(env->regs[9], &sc->arm_r9, err);
1814 __get_user_error(env->regs[10], &sc->arm_r10, err);
1815 __get_user_error(env->regs[11], &sc->arm_fp, err);
1816 __get_user_error(env->regs[12], &sc->arm_ip, err);
1817 __get_user_error(env->regs[13], &sc->arm_sp, err);
1818 __get_user_error(env->regs[14], &sc->arm_lr, err);
1819 __get_user_error(env->regs[15], &sc->arm_pc, err);
1820#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001821 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001822 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001823#endif
1824
1825 err |= !valid_user_regs(env);
1826
1827 return err;
1828}
1829
Andreas Färber05390242012-02-25 03:37:53 +01001830static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001831{
bellardf8b0aa22007-11-11 23:03:42 +00001832 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001833 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001834 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001835 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001836 int i;
bellard43fff232003-07-09 19:31:39 +00001837
1838 /*
1839 * Since we stacked the signal on a 64-bit boundary,
1840 * then 'sp' should be word aligned here. If it's
1841 * not, then the user is trying to mess with us.
1842 */
bellardf8b0aa22007-11-11 23:03:42 +00001843 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001844 if (frame_addr & 7) {
1845 goto badframe;
1846 }
1847
bellardf8b0aa22007-11-11 23:03:42 +00001848 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1849 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001850
bellard92319442004-06-19 16:58:13 +00001851 if (__get_user(set.sig[0], &frame->sc.oldmask))
1852 goto badframe;
1853 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1854 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1855 goto badframe;
1856 }
bellard43fff232003-07-09 19:31:39 +00001857
bellard92319442004-06-19 16:58:13 +00001858 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001859 sigprocmask(SIG_SETMASK, &host_set, NULL);
1860
1861 if (restore_sigcontext(env, &frame->sc))
1862 goto badframe;
1863
1864#if 0
1865 /* Send SIGTRAP if we're single-stepping */
1866 if (ptrace_cancel_bpt(current))
1867 send_sig(SIGTRAP, current, 1);
1868#endif
bellardf8b0aa22007-11-11 23:03:42 +00001869 unlock_user_struct(frame, frame_addr, 0);
1870 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001871
1872badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001873 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001874 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001875 return 0;
1876}
1877
Andreas Färber05390242012-02-25 03:37:53 +01001878static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001879{
1880 int i;
1881 abi_ulong magic, sz;
1882 uint32_t fpscr, fpexc;
1883 struct target_vfp_sigframe *vfpframe;
1884 vfpframe = (struct target_vfp_sigframe *)regspace;
1885
1886 __get_user(magic, &vfpframe->magic);
1887 __get_user(sz, &vfpframe->size);
1888 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1889 return 0;
1890 }
1891 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001892 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001893 }
1894 __get_user(fpscr, &vfpframe->ufp.fpscr);
1895 vfp_set_fpscr(env, fpscr);
1896 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1897 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1898 * and the exception flag is cleared
1899 */
1900 fpexc |= (1 << 30);
1901 fpexc &= ~((1 << 31) | (1 << 28));
1902 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1903 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1904 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1905 return (abi_ulong*)(vfpframe + 1);
1906}
1907
Andreas Färber05390242012-02-25 03:37:53 +01001908static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1909 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001910{
1911 int i;
1912 abi_ulong magic, sz;
1913 struct target_iwmmxt_sigframe *iwmmxtframe;
1914 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1915
1916 __get_user(magic, &iwmmxtframe->magic);
1917 __get_user(sz, &iwmmxtframe->size);
1918 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1919 return 0;
1920 }
1921 for (i = 0; i < 16; i++) {
1922 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1923 }
1924 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1925 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1926 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1927 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1928 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1929 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1930 return (abi_ulong*)(iwmmxtframe + 1);
1931}
1932
Andreas Färber05390242012-02-25 03:37:53 +01001933static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001934 struct target_ucontext_v2 *uc)
1935{
1936 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001937 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001938
1939 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1940 sigprocmask(SIG_SETMASK, &host_set, NULL);
1941
1942 if (restore_sigcontext(env, &uc->tuc_mcontext))
1943 return 1;
1944
Peter Maydell5f9099d2010-11-24 15:20:06 +00001945 /* Restore coprocessor signal frame */
1946 regspace = uc->tuc_regspace;
1947 if (arm_feature(env, ARM_FEATURE_VFP)) {
1948 regspace = restore_sigframe_v2_vfp(env, regspace);
1949 if (!regspace) {
1950 return 1;
1951 }
1952 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001953 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1954 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1955 if (!regspace) {
1956 return 1;
1957 }
1958 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001959
pbrooka8c33202008-05-07 23:22:46 +00001960 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1961 return 1;
1962
1963#if 0
1964 /* Send SIGTRAP if we're single-stepping */
1965 if (ptrace_cancel_bpt(current))
1966 send_sig(SIGTRAP, current, 1);
1967#endif
1968
1969 return 0;
1970}
1971
Andreas Färber05390242012-02-25 03:37:53 +01001972static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001973{
1974 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001975 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00001976
1977 /*
1978 * Since we stacked the signal on a 64-bit boundary,
1979 * then 'sp' should be word aligned here. If it's
1980 * not, then the user is trying to mess with us.
1981 */
pbrooka8c33202008-05-07 23:22:46 +00001982 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001983 if (frame_addr & 7) {
1984 goto badframe;
1985 }
1986
pbrooka8c33202008-05-07 23:22:46 +00001987 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1988 goto badframe;
1989
1990 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1991 goto badframe;
1992
1993 unlock_user_struct(frame, frame_addr, 0);
1994 return env->regs[0];
1995
1996badframe:
1997 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001998 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00001999 return 0;
2000}
2001
Andreas Färber05390242012-02-25 03:37:53 +01002002long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002003{
2004 if (get_osversion() >= 0x020612) {
2005 return do_sigreturn_v2(env);
2006 } else {
2007 return do_sigreturn_v1(env);
2008 }
2009}
2010
Andreas Färber05390242012-02-25 03:37:53 +01002011static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002012{
bellardf8b0aa22007-11-11 23:03:42 +00002013 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002014 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002015 sigset_t host_set;
2016
2017 /*
2018 * Since we stacked the signal on a 64-bit boundary,
2019 * then 'sp' should be word aligned here. If it's
2020 * not, then the user is trying to mess with us.
2021 */
bellardf8b0aa22007-11-11 23:03:42 +00002022 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002023 if (frame_addr & 7) {
2024 goto badframe;
2025 }
2026
bellardf8b0aa22007-11-11 23:03:42 +00002027 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2028 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002029
bellardb8076a72005-04-07 22:20:31 +00002030 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00002031 sigprocmask(SIG_SETMASK, &host_set, NULL);
2032
bellardb8076a72005-04-07 22:20:31 +00002033 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002034 goto badframe;
2035
pbrooka745ec62008-05-06 15:36:17 +00002036 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 +00002037 goto badframe;
2038
bellard43fff232003-07-09 19:31:39 +00002039#if 0
2040 /* Send SIGTRAP if we're single-stepping */
2041 if (ptrace_cancel_bpt(current))
2042 send_sig(SIGTRAP, current, 1);
2043#endif
bellardf8b0aa22007-11-11 23:03:42 +00002044 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002045 return env->regs[0];
2046
2047badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002048 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002049 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002050 return 0;
2051}
2052
Andreas Färber05390242012-02-25 03:37:53 +01002053static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002054{
2055 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002056 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002057
2058 /*
2059 * Since we stacked the signal on a 64-bit boundary,
2060 * then 'sp' should be word aligned here. If it's
2061 * not, then the user is trying to mess with us.
2062 */
pbrooka745ec62008-05-06 15:36:17 +00002063 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002064 if (frame_addr & 7) {
2065 goto badframe;
2066 }
2067
pbrooka745ec62008-05-06 15:36:17 +00002068 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2069 goto badframe;
2070
pbrooka8c33202008-05-07 23:22:46 +00002071 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2072 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002073
pbrooka745ec62008-05-06 15:36:17 +00002074 unlock_user_struct(frame, frame_addr, 0);
2075 return env->regs[0];
2076
2077badframe:
2078 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002079 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002080 return 0;
2081}
2082
Andreas Färber05390242012-02-25 03:37:53 +01002083long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002084{
2085 if (get_osversion() >= 0x020612) {
2086 return do_rt_sigreturn_v2(env);
2087 } else {
2088 return do_rt_sigreturn_v1(env);
2089 }
2090}
2091
bellard6d5e2162004-09-30 22:04:13 +00002092#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002093
bellard6d5e2162004-09-30 22:04:13 +00002094#define __SUNOS_MAXWIN 31
2095
2096/* This is what SunOS does, so shall I. */
2097struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002098 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002099
blueswir1992f48a2007-10-14 16:27:31 +00002100 abi_ulong sigc_mask; /* sigmask to restore */
2101 abi_ulong sigc_sp; /* stack pointer */
2102 abi_ulong sigc_pc; /* program counter */
2103 abi_ulong sigc_npc; /* next program counter */
2104 abi_ulong sigc_psr; /* for condition codes etc */
2105 abi_ulong sigc_g1; /* User uses these two registers */
2106 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002107
2108 /* Now comes information regarding the users window set
2109 * at the time of the signal.
2110 */
blueswir1992f48a2007-10-14 16:27:31 +00002111 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002112
2113 /* stack ptrs for each regwin buf */
2114 char *sigc_spbuf[__SUNOS_MAXWIN];
2115
2116 /* Windows to restore after signal */
2117 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002118 abi_ulong locals[8];
2119 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002120 } sigc_wbuf[__SUNOS_MAXWIN];
2121};
2122/* A Sparc stack frame */
2123struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002124 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002125 abi_ulong ins[8];
2126 /* It's simpler to treat fp and callers_pc as elements of ins[]
2127 * since we never need to access them ourselves.
2128 */
bellard6d5e2162004-09-30 22:04:13 +00002129 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002130 abi_ulong xargs[6];
2131 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002132};
2133
2134typedef struct {
2135 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002136 abi_ulong psr;
2137 abi_ulong pc;
2138 abi_ulong npc;
2139 abi_ulong y;
2140 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002141 } si_regs;
2142 int si_mask;
2143} __siginfo_t;
2144
2145typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002146 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002147 unsigned long si_fsr;
2148 unsigned long si_fpqdepth;
2149 struct {
2150 unsigned long *insn_addr;
2151 unsigned long insn;
2152 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002153} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002154
2155
2156struct target_signal_frame {
2157 struct sparc_stackf ss;
2158 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002159 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002160 abi_ulong insns[2] __attribute__ ((aligned (8)));
2161 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2162 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002163 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002164};
2165struct target_rt_signal_frame {
2166 struct sparc_stackf ss;
2167 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002168 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002169 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002170 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002171 unsigned int insns[2];
2172 stack_t stack;
2173 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002174 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002175};
2176
bellarde80cfcf2004-12-19 23:18:01 +00002177#define UREG_O0 16
2178#define UREG_O6 22
2179#define UREG_I0 0
2180#define UREG_I1 1
2181#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002182#define UREG_I3 3
2183#define UREG_I4 4
2184#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002185#define UREG_I6 6
2186#define UREG_I7 7
2187#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002188#define UREG_FP UREG_I6
2189#define UREG_SP UREG_O6
2190
pbrook624f7972008-05-31 16:11:38 +00002191static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002192 CPUSPARCState *env,
2193 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002194{
bellard459a4012007-11-11 19:45:10 +00002195 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002196
2197 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002198
2199 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002200 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002201 if (!on_sig_stack(sp)
2202 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2203 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002204 }
bellard459a4012007-11-11 19:45:10 +00002205 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002206}
2207
2208static int
Andreas Färber05390242012-02-25 03:37:53 +01002209setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002210{
2211 int err = 0, i;
2212
bellard6d5e2162004-09-30 22:04:13 +00002213 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00002214 err |= __put_user(env->pc, &si->si_regs.pc);
2215 err |= __put_user(env->npc, &si->si_regs.npc);
2216 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002217 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00002218 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
2219 }
bellarda315a142005-01-30 22:59:18 +00002220 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002221 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002222 }
bellard6d5e2162004-09-30 22:04:13 +00002223 err |= __put_user(mask, &si->si_mask);
2224 return err;
2225}
bellarde80cfcf2004-12-19 23:18:01 +00002226
bellard80a9d032005-01-03 23:31:27 +00002227#if 0
bellard6d5e2162004-09-30 22:04:13 +00002228static int
2229setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002230 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002231{
2232 int err = 0;
2233
2234 err |= __put_user(mask, &sc->sigc_mask);
2235 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2236 err |= __put_user(env->pc, &sc->sigc_pc);
2237 err |= __put_user(env->npc, &sc->sigc_npc);
2238 err |= __put_user(env->psr, &sc->sigc_psr);
2239 err |= __put_user(env->gregs[1], &sc->sigc_g1);
2240 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
2241
2242 return err;
2243}
bellard80a9d032005-01-03 23:31:27 +00002244#endif
bellard6d5e2162004-09-30 22:04:13 +00002245#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2246
pbrook624f7972008-05-31 16:11:38 +00002247static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002248 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002249{
bellard459a4012007-11-11 19:45:10 +00002250 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002251 struct target_signal_frame *sf;
2252 int sigframe_size, err, i;
2253
2254 /* 1. Make sure everything is clean */
2255 //synchronize_user_stack();
2256
2257 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002258 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002259
bellard459a4012007-11-11 19:45:10 +00002260 sf = lock_user(VERIFY_WRITE, sf_addr,
2261 sizeof(struct target_signal_frame), 0);
2262 if (!sf)
2263 goto sigsegv;
2264
bellarde80cfcf2004-12-19 23:18:01 +00002265 //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 +00002266#if 0
2267 if (invalid_frame_pointer(sf, sigframe_size))
2268 goto sigill_and_return;
2269#endif
2270 /* 2. Save the current process state */
2271 err = setup___siginfo(&sf->info, env, set->sig[0]);
2272 err |= __put_user(0, &sf->extra_size);
2273
2274 //err |= save_fpu_state(regs, &sf->fpu_state);
2275 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
2276
2277 err |= __put_user(set->sig[0], &sf->info.si_mask);
2278 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2279 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
2280 }
2281
bellarda315a142005-01-30 22:59:18 +00002282 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002283 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002284 }
bellarda315a142005-01-30 22:59:18 +00002285 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002286 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002287 }
bellard6d5e2162004-09-30 22:04:13 +00002288 if (err)
2289 goto sigsegv;
2290
2291 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002292 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002293 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002294 env->regwptr[UREG_I1] = sf_addr +
2295 offsetof(struct target_signal_frame, info);
2296 env->regwptr[UREG_I2] = sf_addr +
2297 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002298
2299 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002300 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002301 env->npc = (env->pc + 4);
2302 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002303 if (ka->sa_restorer)
2304 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002305 else {
bellard775b58d2007-11-11 16:22:17 +00002306 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002307
2308 env->regwptr[UREG_I7] = sf_addr +
2309 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002310
2311 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002312 val32 = 0x821020d8;
2313 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002314
2315 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002316 val32 = 0x91d02010;
2317 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002318 if (err)
2319 goto sigsegv;
2320
2321 /* Flush instruction space. */
2322 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002323 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002324 }
bellard459a4012007-11-11 19:45:10 +00002325 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002326 return;
bellard459a4012007-11-11 19:45:10 +00002327#if 0
2328sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002329 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002330#endif
bellard6d5e2162004-09-30 22:04:13 +00002331sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002332 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002333 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002334 force_sig(TARGET_SIGSEGV);
2335}
2336static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002337restore_fpu_state(CPUSPARCState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00002338{
2339 int err;
2340#if 0
2341#ifdef CONFIG_SMP
2342 if (current->flags & PF_USEDFPU)
2343 regs->psr &= ~PSR_EF;
2344#else
2345 if (current == last_task_used_math) {
2346 last_task_used_math = 0;
2347 regs->psr &= ~PSR_EF;
2348 }
2349#endif
2350 current->used_math = 1;
2351 current->flags &= ~PF_USEDFPU;
2352#endif
2353#if 0
2354 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
2355 return -EFAULT;
2356#endif
2357
bellardfafffae2006-10-28 12:09:16 +00002358 /* XXX: incorrect */
Blue Swirl8954bae2012-07-30 15:29:11 +00002359 err = copy_from_user(&env->fpr[0], fpu->si_float_regs[0],
2360 (sizeof(abi_ulong) * 32));
bellard6d5e2162004-09-30 22:04:13 +00002361 err |= __get_user(env->fsr, &fpu->si_fsr);
2362#if 0
2363 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
2364 if (current->thread.fpqdepth != 0)
2365 err |= __copy_from_user(&current->thread.fpqueue[0],
2366 &fpu->si_fpqueue[0],
2367 ((sizeof(unsigned long) +
2368 (sizeof(unsigned long *)))*16));
2369#endif
2370 return err;
2371}
2372
2373
pbrook624f7972008-05-31 16:11:38 +00002374static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002375 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002376 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002377{
2378 fprintf(stderr, "setup_rt_frame: not implemented\n");
2379}
2380
Andreas Färber05390242012-02-25 03:37:53 +01002381long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002382{
bellardf8b0aa22007-11-11 23:03:42 +00002383 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002384 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002385 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002386 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002387 sigset_t host_set;
bellarde80cfcf2004-12-19 23:18:01 +00002388 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00002389
bellardf8b0aa22007-11-11 23:03:42 +00002390 sf_addr = env->regwptr[UREG_FP];
2391 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2392 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002393#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002394 fprintf(stderr, "sigreturn\n");
2395 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 +00002396#endif
bellarde80cfcf2004-12-19 23:18:01 +00002397 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002398
2399 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002400
bellardf8b0aa22007-11-11 23:03:42 +00002401 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002402 goto segv_and_exit;
2403
2404 err = __get_user(pc, &sf->info.si_regs.pc);
2405 err |= __get_user(npc, &sf->info.si_regs.npc);
2406
bellard6d5e2162004-09-30 22:04:13 +00002407 if ((pc | npc) & 3)
2408 goto segv_and_exit;
2409
2410 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00002411 err |= __get_user(up_psr, &sf->info.si_regs.psr);
2412
bellard6d5e2162004-09-30 22:04:13 +00002413 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002414 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2415 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2416
2417 env->pc = pc;
2418 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00002419 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002420 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002421 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2422 }
bellarda315a142005-01-30 22:59:18 +00002423 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002424 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2425 }
bellard6d5e2162004-09-30 22:04:13 +00002426
Peter Maydell2aec3a22011-06-16 17:37:14 +01002427 /* FIXME: implement FPU save/restore:
2428 * __get_user(fpu_save, &sf->fpu_save);
2429 * if (fpu_save)
2430 * err |= restore_fpu_state(env, fpu_save);
2431 */
bellard6d5e2162004-09-30 22:04:13 +00002432
2433 /* This is pretty much atomic, no amount locking would prevent
2434 * the races which exist anyways.
2435 */
2436 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002437 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2438 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
2439 }
2440
2441 target_to_host_sigset_internal(&host_set, &set);
2442 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002443
2444 if (err)
2445 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002446 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002447 return env->regwptr[0];
2448
2449segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002450 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002451 force_sig(TARGET_SIGSEGV);
2452}
2453
Andreas Färber05390242012-02-25 03:37:53 +01002454long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002455{
2456 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002457 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002458}
2459
bellard459a4012007-11-11 19:45:10 +00002460#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002461#define MC_TSTATE 0
2462#define MC_PC 1
2463#define MC_NPC 2
2464#define MC_Y 3
2465#define MC_G1 4
2466#define MC_G2 5
2467#define MC_G3 6
2468#define MC_G4 7
2469#define MC_G5 8
2470#define MC_G6 9
2471#define MC_G7 10
2472#define MC_O0 11
2473#define MC_O1 12
2474#define MC_O2 13
2475#define MC_O3 14
2476#define MC_O4 15
2477#define MC_O5 16
2478#define MC_O6 17
2479#define MC_O7 18
2480#define MC_NGREG 19
2481
Anthony Liguoric227f092009-10-01 16:12:16 -05002482typedef abi_ulong target_mc_greg_t;
2483typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002484
2485struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002486 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002487 uint32_t mcfq_insn;
2488};
2489
2490struct target_mc_fpu {
2491 union {
2492 uint32_t sregs[32];
2493 uint64_t dregs[32];
2494 //uint128_t qregs[16];
2495 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002496 abi_ulong mcfpu_fsr;
2497 abi_ulong mcfpu_fprs;
2498 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002499 struct target_mc_fq *mcfpu_fq;
2500 unsigned char mcfpu_qcnt;
2501 unsigned char mcfpu_qentsz;
2502 unsigned char mcfpu_enab;
2503};
Anthony Liguoric227f092009-10-01 16:12:16 -05002504typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002505
2506typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002507 target_mc_gregset_t mc_gregs;
2508 target_mc_greg_t mc_fp;
2509 target_mc_greg_t mc_i7;
2510 target_mc_fpu_t mc_fpregs;
2511} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002512
2513struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002514 struct target_ucontext *tuc_link;
2515 abi_ulong tuc_flags;
2516 target_sigset_t tuc_sigmask;
2517 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002518};
2519
2520/* A V9 register window */
2521struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002522 abi_ulong locals[8];
2523 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002524};
2525
2526#define TARGET_STACK_BIAS 2047
2527
2528/* {set, get}context() needed for 64-bit SparcLinux userland. */
2529void sparc64_set_context(CPUSPARCState *env)
2530{
bellard459a4012007-11-11 19:45:10 +00002531 abi_ulong ucp_addr;
2532 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002533 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002534 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002535 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002536 int err;
2537 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002538
bellard459a4012007-11-11 19:45:10 +00002539 ucp_addr = env->regwptr[UREG_I0];
2540 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2541 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002542 grp = &ucp->tuc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002543 err = __get_user(pc, &((*grp)[MC_PC]));
2544 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002545 if (err || ((pc | npc) & 3))
2546 goto do_sigsegv;
2547 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002548 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002549 sigset_t set;
2550
2551 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002552 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002553 goto do_sigsegv;
2554 } else {
bellard459a4012007-11-11 19:45:10 +00002555 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002556 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002557 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002558 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002559 err |= __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002560 }
blueswir15bfb56b2007-10-05 17:01:51 +00002561 if (err)
2562 goto do_sigsegv;
2563 }
2564 target_to_host_sigset_internal(&set, &target_set);
2565 sigprocmask(SIG_SETMASK, &set, NULL);
2566 }
2567 env->pc = pc;
2568 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002569 err |= __get_user(env->y, &((*grp)[MC_Y]));
2570 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002571 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002572 cpu_put_ccr(env, tstate >> 32);
2573 cpu_put_cwp64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002574 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2575 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2576 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2577 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2578 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2579 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2580 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2581 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2582 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2583 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2584 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2585 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2586 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2587 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2588 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002589
Aurelien Jarno60e99242010-03-29 02:12:51 +02002590 err |= __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2591 err |= __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002592
bellard459a4012007-11-11 19:45:10 +00002593 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2594 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2595 abi_ulong) != 0)
2596 goto do_sigsegv;
2597 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2598 abi_ulong) != 0)
2599 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002600 /* FIXME this does not match how the kernel handles the FPU in
2601 * its sparc64_set_context implementation. In particular the FPU
2602 * is only restored if fenab is non-zero in:
2603 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2604 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002605 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002606 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002607 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2608 for (i = 0; i < 64; i++, src++) {
2609 if (i & 1) {
2610 err |= __get_user(env->fpr[i/2].l.lower, src);
2611 } else {
2612 err |= __get_user(env->fpr[i/2].l.upper, src);
2613 }
2614 }
bellard459a4012007-11-11 19:45:10 +00002615 }
bellard579a97f2007-11-11 14:26:47 +00002616 err |= __get_user(env->fsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002617 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
bellard579a97f2007-11-11 14:26:47 +00002618 err |= __get_user(env->gsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002619 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002620 if (err)
2621 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002622 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002623 return;
2624 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002625 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002626 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002627}
2628
2629void sparc64_get_context(CPUSPARCState *env)
2630{
bellard459a4012007-11-11 19:45:10 +00002631 abi_ulong ucp_addr;
2632 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002633 target_mc_gregset_t *grp;
2634 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002635 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002636 int err;
2637 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002638 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002639 sigset_t set;
2640
bellard459a4012007-11-11 19:45:10 +00002641 ucp_addr = env->regwptr[UREG_I0];
2642 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2643 goto do_sigsegv;
2644
Aurelien Jarno60e99242010-03-29 02:12:51 +02002645 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002646 grp = &mcp->mc_gregs;
2647
2648 /* Skip over the trap instruction, first. */
2649 env->pc = env->npc;
2650 env->npc += 4;
2651
2652 err = 0;
2653
2654 sigprocmask(0, NULL, &set);
2655 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002656 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002657 err |= __put_user(target_set.sig[0],
Aurelien Jarno60e99242010-03-29 02:12:51 +02002658 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002659 } else {
2660 abi_ulong *src, *dst;
2661 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002662 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002663 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002664 err |= __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002665 }
blueswir15bfb56b2007-10-05 17:01:51 +00002666 if (err)
2667 goto do_sigsegv;
2668 }
2669
bellard459a4012007-11-11 19:45:10 +00002670 /* XXX: tstate must be saved properly */
2671 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002672 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2673 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2674 err |= __put_user(env->y, &((*grp)[MC_Y]));
2675 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2676 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2677 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2678 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2679 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2680 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2681 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2682 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2683 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2684 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2685 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2686 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2687 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2688 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2689 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002690
bellard459a4012007-11-11 19:45:10 +00002691 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2692 fp = i7 = 0;
2693 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2694 abi_ulong) != 0)
2695 goto do_sigsegv;
2696 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2697 abi_ulong) != 0)
2698 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002699 err |= __put_user(fp, &(mcp->mc_fp));
2700 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002701
bellard459a4012007-11-11 19:45:10 +00002702 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002703 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2704 for (i = 0; i < 64; i++, dst++) {
2705 if (i & 1) {
2706 err |= __put_user(env->fpr[i/2].l.lower, dst);
2707 } else {
2708 err |= __put_user(env->fpr[i/2].l.upper, dst);
2709 }
2710 }
bellard459a4012007-11-11 19:45:10 +00002711 }
bellard579a97f2007-11-11 14:26:47 +00002712 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2713 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2714 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002715
2716 if (err)
2717 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002718 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002719 return;
2720 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002721 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002722 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002723}
2724#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002725#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002726
Richard Hendersonff970902013-02-10 10:30:42 -08002727# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002728struct target_sigcontext {
2729 uint32_t sc_regmask; /* Unused */
2730 uint32_t sc_status;
2731 uint64_t sc_pc;
2732 uint64_t sc_regs[32];
2733 uint64_t sc_fpregs[32];
2734 uint32_t sc_ownedfp; /* Unused */
2735 uint32_t sc_fpc_csr;
2736 uint32_t sc_fpc_eir; /* Unused */
2737 uint32_t sc_used_math;
2738 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002739 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002740 uint64_t sc_mdhi;
2741 uint64_t sc_mdlo;
2742 target_ulong sc_hi1; /* Was sc_cause */
2743 target_ulong sc_lo1; /* Was sc_badvaddr */
2744 target_ulong sc_hi2; /* Was sc_sigset[4] */
2745 target_ulong sc_lo2;
2746 target_ulong sc_hi3;
2747 target_ulong sc_lo3;
2748};
Richard Hendersonff970902013-02-10 10:30:42 -08002749# else /* N32 || N64 */
2750struct target_sigcontext {
2751 uint64_t sc_regs[32];
2752 uint64_t sc_fpregs[32];
2753 uint64_t sc_mdhi;
2754 uint64_t sc_hi1;
2755 uint64_t sc_hi2;
2756 uint64_t sc_hi3;
2757 uint64_t sc_mdlo;
2758 uint64_t sc_lo1;
2759 uint64_t sc_lo2;
2760 uint64_t sc_lo3;
2761 uint64_t sc_pc;
2762 uint32_t sc_fpc_csr;
2763 uint32_t sc_used_math;
2764 uint32_t sc_dsp;
2765 uint32_t sc_reserved;
2766};
2767# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002768
2769struct sigframe {
2770 uint32_t sf_ass[4]; /* argument save space for o32 */
2771 uint32_t sf_code[2]; /* signal trampoline */
2772 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002773 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002774};
2775
pbrook0b1bcb02009-04-21 01:41:10 +00002776struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002777 target_ulong tuc_flags;
2778 target_ulong tuc_link;
2779 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002780 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002781 struct target_sigcontext tuc_mcontext;
2782 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002783};
2784
2785struct target_rt_sigframe {
2786 uint32_t rs_ass[4]; /* argument save space for o32 */
2787 uint32_t rs_code[2]; /* signal trampoline */
2788 struct target_siginfo rs_info;
2789 struct target_ucontext rs_uc;
2790};
2791
bellard106ec872006-06-27 21:08:10 +00002792/* Install trampoline to jump back from signal handler */
2793static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2794{
Richard Henderson084d0492013-02-10 10:30:44 -08002795 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002796
2797 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002798 * Set up the return code ...
2799 *
2800 * li v0, __NR__foo_sigreturn
2801 * syscall
2802 */
bellard106ec872006-06-27 21:08:10 +00002803
Richard Henderson084d0492013-02-10 10:30:44 -08002804 err |= __put_user(0x24020000 + syscall, tramp + 0);
bellard106ec872006-06-27 21:08:10 +00002805 err |= __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002806 return err;
2807}
2808
2809static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002810setup_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002811{
2812 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002813 int i;
bellard106ec872006-06-27 21:08:10 +00002814
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002815 err |= __put_user(exception_resume_pc(regs), &sc->sc_pc);
2816 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002817
Richard Henderson084d0492013-02-10 10:30:44 -08002818 __put_user(0, &sc->sc_regs[0]);
2819 for (i = 1; i < 32; ++i) {
2820 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
2821 }
bellard106ec872006-06-27 21:08:10 +00002822
thsb5dc7732008-06-27 10:02:35 +00002823 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2824 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002825
Richard Henderson084d0492013-02-10 10:30:44 -08002826 /* Rather than checking for dsp existence, always copy. The storage
2827 would just be garbage otherwise. */
2828 err |= __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2829 err |= __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2830 err |= __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2831 err |= __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2832 err |= __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2833 err |= __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
2834 {
2835 uint32_t dsp = cpu_rddsp(0x3ff, regs);
2836 err |= __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002837 }
Richard Henderson084d0492013-02-10 10:30:44 -08002838
2839 err |= __put_user(1, &sc->sc_used_math);
2840
2841 for (i = 0; i < 32; ++i) {
2842 err |= __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002843 }
bellard106ec872006-06-27 21:08:10 +00002844
bellard106ec872006-06-27 21:08:10 +00002845 return err;
2846}
2847
2848static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002849restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002850{
2851 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002852 int i;
bellard106ec872006-06-27 21:08:10 +00002853
2854 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2855
thsb5dc7732008-06-27 10:02:35 +00002856 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2857 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002858
Richard Henderson084d0492013-02-10 10:30:44 -08002859 for (i = 1; i < 32; ++i) {
2860 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002861 }
2862
Richard Henderson084d0492013-02-10 10:30:44 -08002863 err |= __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2864 err |= __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2865 err |= __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2866 err |= __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2867 err |= __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2868 err |= __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
2869 {
2870 uint32_t dsp;
2871 err |= __get_user(dsp, &sc->sc_dsp);
2872 cpu_wrdsp(dsp, 0x3ff, regs);
2873 }
2874
2875 for (i = 0; i < 32; ++i) {
2876 err |= __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
2877 }
2878
bellard106ec872006-06-27 21:08:10 +00002879 return err;
2880}
Richard Hendersonff970902013-02-10 10:30:42 -08002881
bellard106ec872006-06-27 21:08:10 +00002882/*
2883 * Determine which stack to use..
2884 */
bellard579a97f2007-11-11 14:26:47 +00002885static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002886get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002887{
2888 unsigned long sp;
2889
2890 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002891 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002892
2893 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002894 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002895 * above the user stack, 16-bytes before the next lowest
2896 * 16 byte boundary. Try to avoid trashing it.
2897 */
2898 sp -= 32;
2899
bellard106ec872006-06-27 21:08:10 +00002900 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002901 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002902 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2903 }
bellard106ec872006-06-27 21:08:10 +00002904
bellard579a97f2007-11-11 14:26:47 +00002905 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002906}
2907
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002908static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2909{
2910 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2911 env->hflags &= ~MIPS_HFLAG_M16;
2912 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2913 env->active_tc.PC &= ~(target_ulong) 1;
2914 }
2915}
2916
Richard Hendersonff970902013-02-10 10:30:42 -08002917# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002918/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002919static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002920 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002921{
2922 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002923 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002924 int i;
2925
bellard579a97f2007-11-11 14:26:47 +00002926 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2927 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002928 goto give_sigsegv;
2929
2930 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2931
2932 if(setup_sigcontext(regs, &frame->sf_sc))
2933 goto give_sigsegv;
2934
2935 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2936 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2937 goto give_sigsegv;
2938 }
2939
2940 /*
2941 * Arguments to signal handler:
2942 *
2943 * a0 = signal number
2944 * a1 = 0 (should be cause)
2945 * a2 = pointer to struct sigcontext
2946 *
2947 * $25 and PC point to the signal handler, $29 points to the
2948 * struct sigframe.
2949 */
thsb5dc7732008-06-27 10:02:35 +00002950 regs->active_tc.gpr[ 4] = sig;
2951 regs->active_tc.gpr[ 5] = 0;
2952 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2953 regs->active_tc.gpr[29] = frame_addr;
2954 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002955 /* The original kernel code sets CP0_EPC to the handler
2956 * since it returns to userland using eret
2957 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002958 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002959 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002960 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002961 return;
2962
2963give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002964 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002965 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002966}
2967
Andreas Färber05390242012-02-25 03:37:53 +01002968long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002969{
ths388bb212007-05-13 13:58:00 +00002970 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002971 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002972 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002973 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002974 int i;
bellard106ec872006-06-27 21:08:10 +00002975
2976#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002977 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002978#endif
thsb5dc7732008-06-27 10:02:35 +00002979 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002980 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002981 goto badframe;
2982
ths388bb212007-05-13 13:58:00 +00002983 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002984 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2985 goto badframe;
ths388bb212007-05-13 13:58:00 +00002986 }
bellard106ec872006-06-27 21:08:10 +00002987
ths388bb212007-05-13 13:58:00 +00002988 target_to_host_sigset_internal(&blocked, &target_set);
2989 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002990
ths388bb212007-05-13 13:58:00 +00002991 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002992 goto badframe;
2993
2994#if 0
ths388bb212007-05-13 13:58:00 +00002995 /*
2996 * Don't let your children do this ...
2997 */
2998 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002999 "move\t$29, %0\n\t"
3000 "j\tsyscall_exit"
3001 :/* no outputs */
3002 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003003 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003004#endif
ths3b46e622007-09-17 08:09:54 +00003005
thsb5dc7732008-06-27 10:02:35 +00003006 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003007 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003008 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003009 * maybe a problem with nested signals ? */
3010 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003011 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003012
3013badframe:
ths388bb212007-05-13 13:58:00 +00003014 force_sig(TARGET_SIGSEGV/*, current*/);
3015 return 0;
bellard106ec872006-06-27 21:08:10 +00003016}
Richard Hendersonff970902013-02-10 10:30:42 -08003017# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003018
pbrook624f7972008-05-31 16:11:38 +00003019static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003020 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003021 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003022{
pbrook0b1bcb02009-04-21 01:41:10 +00003023 struct target_rt_sigframe *frame;
3024 abi_ulong frame_addr;
3025 int i;
3026
3027 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3028 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3029 goto give_sigsegv;
3030
3031 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3032
3033 copy_siginfo_to_user(&frame->rs_info, info);
3034
Aurelien Jarno60e99242010-03-29 02:12:51 +02003035 __put_user(0, &frame->rs_uc.tuc_flags);
3036 __put_user(0, &frame->rs_uc.tuc_link);
3037 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3038 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003039 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003040 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003041
Aurelien Jarno60e99242010-03-29 02:12:51 +02003042 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003043
3044 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003045 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003046 }
3047
3048 /*
3049 * Arguments to signal handler:
3050 *
3051 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003052 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003053 * a2 = pointer to struct ucontext
3054 *
3055 * $25 and PC point to the signal handler, $29 points to the
3056 * struct sigframe.
3057 */
3058 env->active_tc.gpr[ 4] = sig;
3059 env->active_tc.gpr[ 5] = frame_addr
3060 + offsetof(struct target_rt_sigframe, rs_info);
3061 env->active_tc.gpr[ 6] = frame_addr
3062 + offsetof(struct target_rt_sigframe, rs_uc);
3063 env->active_tc.gpr[29] = frame_addr;
3064 env->active_tc.gpr[31] = frame_addr
3065 + offsetof(struct target_rt_sigframe, rs_code);
3066 /* The original kernel code sets CP0_EPC to the handler
3067 * since it returns to userland using eret
3068 * we cannot do this here, and we must set PC directly */
3069 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003070 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003071 unlock_user_struct(frame, frame_addr, 1);
3072 return;
3073
3074give_sigsegv:
3075 unlock_user_struct(frame, frame_addr, 1);
3076 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003077}
3078
Andreas Färber05390242012-02-25 03:37:53 +01003079long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003080{
pbrook0b1bcb02009-04-21 01:41:10 +00003081 struct target_rt_sigframe *frame;
3082 abi_ulong frame_addr;
3083 sigset_t blocked;
3084
3085#if defined(DEBUG_SIGNAL)
3086 fprintf(stderr, "do_rt_sigreturn\n");
3087#endif
3088 frame_addr = env->active_tc.gpr[29];
3089 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3090 goto badframe;
3091
Aurelien Jarno60e99242010-03-29 02:12:51 +02003092 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
pbrook0b1bcb02009-04-21 01:41:10 +00003093 sigprocmask(SIG_SETMASK, &blocked, NULL);
3094
Aurelien Jarno60e99242010-03-29 02:12:51 +02003095 if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
pbrook0b1bcb02009-04-21 01:41:10 +00003096 goto badframe;
3097
3098 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003099 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003100 0, get_sp_from_cpustate(env)) == -EFAULT)
3101 goto badframe;
3102
3103 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003104 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003105 /* I am not sure this is right, but it seems to work
3106 * maybe a problem with nested signals ? */
3107 env->CP0_EPC = 0;
3108 return -TARGET_QEMU_ESIGRETURN;
3109
3110badframe:
3111 force_sig(TARGET_SIGSEGV/*, current*/);
3112 return 0;
bellard106ec872006-06-27 21:08:10 +00003113}
bellard6d5e2162004-09-30 22:04:13 +00003114
thsc3b5bc82007-12-02 06:31:25 +00003115#elif defined(TARGET_SH4)
3116
3117/*
3118 * code and data structures from linux kernel:
3119 * include/asm-sh/sigcontext.h
3120 * arch/sh/kernel/signal.c
3121 */
3122
3123struct target_sigcontext {
3124 target_ulong oldmask;
3125
3126 /* CPU registers */
3127 target_ulong sc_gregs[16];
3128 target_ulong sc_pc;
3129 target_ulong sc_pr;
3130 target_ulong sc_sr;
3131 target_ulong sc_gbr;
3132 target_ulong sc_mach;
3133 target_ulong sc_macl;
3134
3135 /* FPU registers */
3136 target_ulong sc_fpregs[16];
3137 target_ulong sc_xfpregs[16];
3138 unsigned int sc_fpscr;
3139 unsigned int sc_fpul;
3140 unsigned int sc_ownedfp;
3141};
3142
3143struct target_sigframe
3144{
3145 struct target_sigcontext sc;
3146 target_ulong extramask[TARGET_NSIG_WORDS-1];
3147 uint16_t retcode[3];
3148};
3149
3150
3151struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003152 target_ulong tuc_flags;
3153 struct target_ucontext *tuc_link;
3154 target_stack_t tuc_stack;
3155 struct target_sigcontext tuc_mcontext;
3156 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003157};
3158
3159struct target_rt_sigframe
3160{
3161 struct target_siginfo info;
3162 struct target_ucontext uc;
3163 uint16_t retcode[3];
3164};
3165
3166
3167#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3168#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3169
pbrook624f7972008-05-31 16:11:38 +00003170static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003171 unsigned long sp, size_t frame_size)
3172{
pbrook624f7972008-05-31 16:11:38 +00003173 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003174 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3175 }
3176
3177 return (sp - frame_size) & -8ul;
3178}
3179
3180static int setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003181 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003182{
3183 int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003184 int i;
thsc3b5bc82007-12-02 06:31:25 +00003185
3186#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
3187 COPY(gregs[0]); COPY(gregs[1]);
3188 COPY(gregs[2]); COPY(gregs[3]);
3189 COPY(gregs[4]); COPY(gregs[5]);
3190 COPY(gregs[6]); COPY(gregs[7]);
3191 COPY(gregs[8]); COPY(gregs[9]);
3192 COPY(gregs[10]); COPY(gregs[11]);
3193 COPY(gregs[12]); COPY(gregs[13]);
3194 COPY(gregs[14]); COPY(gregs[15]);
3195 COPY(gbr); COPY(mach);
3196 COPY(macl); COPY(pr);
3197 COPY(sr); COPY(pc);
3198#undef COPY
3199
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003200 for (i=0; i<16; i++) {
3201 err |= __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
3202 }
3203 err |= __put_user(regs->fpscr, &sc->sc_fpscr);
3204 err |= __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003205
3206 /* non-iBCS2 extensions.. */
3207 err |= __put_user(mask, &sc->oldmask);
3208
3209 return err;
3210}
3211
Andreas Färber05390242012-02-25 03:37:53 +01003212static int restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003213 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003214{
3215 unsigned int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003216 int i;
thsc3b5bc82007-12-02 06:31:25 +00003217
3218#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
3219 COPY(gregs[1]);
3220 COPY(gregs[2]); COPY(gregs[3]);
3221 COPY(gregs[4]); COPY(gregs[5]);
3222 COPY(gregs[6]); COPY(gregs[7]);
3223 COPY(gregs[8]); COPY(gregs[9]);
3224 COPY(gregs[10]); COPY(gregs[11]);
3225 COPY(gregs[12]); COPY(gregs[13]);
3226 COPY(gregs[14]); COPY(gregs[15]);
3227 COPY(gbr); COPY(mach);
3228 COPY(macl); COPY(pr);
3229 COPY(sr); COPY(pc);
3230#undef COPY
3231
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003232 for (i=0; i<16; i++) {
3233 err |= __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
3234 }
3235 err |= __get_user(regs->fpscr, &sc->sc_fpscr);
3236 err |= __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003237
3238 regs->tra = -1; /* disable syscall checks */
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003239 err |= __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003240 return err;
3241}
3242
pbrook624f7972008-05-31 16:11:38 +00003243static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003244 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003245{
3246 struct target_sigframe *frame;
3247 abi_ulong frame_addr;
3248 int i;
3249 int err = 0;
3250 int signal;
3251
3252 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3253 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3254 goto give_sigsegv;
3255
3256 signal = current_exec_domain_sig(sig);
3257
3258 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
3259
3260 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
3261 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
3262 }
3263
3264 /* Set up to return from userspace. If provided, use a stub
3265 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003266 if (ka->sa_flags & TARGET_SA_RESTORER) {
3267 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003268 } else {
3269 /* Generate return code (system call to sigreturn) */
3270 err |= __put_user(MOVW(2), &frame->retcode[0]);
3271 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3272 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
3273 regs->pr = (unsigned long) frame->retcode;
3274 }
3275
3276 if (err)
3277 goto give_sigsegv;
3278
3279 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003280 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003281 regs->gregs[4] = signal; /* Arg for signal handler */
3282 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003283 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003284 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003285
3286 unlock_user_struct(frame, frame_addr, 1);
3287 return;
3288
3289give_sigsegv:
3290 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003291 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003292}
3293
pbrook624f7972008-05-31 16:11:38 +00003294static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003295 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003296 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003297{
3298 struct target_rt_sigframe *frame;
3299 abi_ulong frame_addr;
3300 int i;
3301 int err = 0;
3302 int signal;
3303
3304 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3305 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3306 goto give_sigsegv;
3307
3308 signal = current_exec_domain_sig(sig);
3309
3310 err |= copy_siginfo_to_user(&frame->info, info);
3311
3312 /* Create the ucontext. */
Aurelien Jarno60e99242010-03-29 02:12:51 +02003313 err |= __put_user(0, &frame->uc.tuc_flags);
3314 err |= __put_user(0, (unsigned long *)&frame->uc.tuc_link);
balrog526ccb72008-07-16 12:13:52 +00003315 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003316 &frame->uc.tuc_stack.ss_sp);
thsc3b5bc82007-12-02 06:31:25 +00003317 err |= __put_user(sas_ss_flags(regs->gregs[15]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003318 &frame->uc.tuc_stack.ss_flags);
thsc3b5bc82007-12-02 06:31:25 +00003319 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003320 &frame->uc.tuc_stack.ss_size);
3321 err |= setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003322 regs, set->sig[0]);
3323 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003324 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003325 }
3326
3327 /* Set up to return from userspace. If provided, use a stub
3328 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003329 if (ka->sa_flags & TARGET_SA_RESTORER) {
3330 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003331 } else {
3332 /* Generate return code (system call to sigreturn) */
3333 err |= __put_user(MOVW(2), &frame->retcode[0]);
3334 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3335 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
3336 regs->pr = (unsigned long) frame->retcode;
3337 }
3338
3339 if (err)
3340 goto give_sigsegv;
3341
3342 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003343 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003344 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003345 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3346 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003347 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003348
3349 unlock_user_struct(frame, frame_addr, 1);
3350 return;
3351
3352give_sigsegv:
3353 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003354 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003355}
3356
Andreas Färber05390242012-02-25 03:37:53 +01003357long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003358{
3359 struct target_sigframe *frame;
3360 abi_ulong frame_addr;
3361 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003362 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003363 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003364 int i;
3365 int err = 0;
3366
3367#if defined(DEBUG_SIGNAL)
3368 fprintf(stderr, "do_sigreturn\n");
3369#endif
3370 frame_addr = regs->gregs[15];
3371 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3372 goto badframe;
3373
3374 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
3375 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3376 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
3377 }
3378
3379 if (err)
3380 goto badframe;
3381
3382 target_to_host_sigset_internal(&blocked, &target_set);
3383 sigprocmask(SIG_SETMASK, &blocked, NULL);
3384
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003385 if (restore_sigcontext(regs, &frame->sc, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003386 goto badframe;
3387
3388 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003389 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003390
3391badframe:
3392 unlock_user_struct(frame, frame_addr, 0);
3393 force_sig(TARGET_SIGSEGV);
3394 return 0;
3395}
3396
Andreas Färber05390242012-02-25 03:37:53 +01003397long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003398{
3399 struct target_rt_sigframe *frame;
3400 abi_ulong frame_addr;
3401 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003402 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003403
3404#if defined(DEBUG_SIGNAL)
3405 fprintf(stderr, "do_rt_sigreturn\n");
3406#endif
3407 frame_addr = regs->gregs[15];
3408 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3409 goto badframe;
3410
Aurelien Jarno60e99242010-03-29 02:12:51 +02003411 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
thsc3b5bc82007-12-02 06:31:25 +00003412 sigprocmask(SIG_SETMASK, &blocked, NULL);
3413
Aurelien Jarno60e99242010-03-29 02:12:51 +02003414 if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003415 goto badframe;
3416
3417 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003418 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003419 0, get_sp_from_cpustate(regs)) == -EFAULT)
3420 goto badframe;
3421
3422 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003423 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003424
3425badframe:
3426 unlock_user_struct(frame, frame_addr, 0);
3427 force_sig(TARGET_SIGSEGV);
3428 return 0;
3429}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003430#elif defined(TARGET_MICROBLAZE)
3431
3432struct target_sigcontext {
3433 struct target_pt_regs regs; /* needs to be first */
3434 uint32_t oldmask;
3435};
3436
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003437struct target_stack_t {
3438 abi_ulong ss_sp;
3439 int ss_flags;
3440 unsigned int ss_size;
3441};
3442
3443struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003444 abi_ulong tuc_flags;
3445 abi_ulong tuc_link;
3446 struct target_stack_t tuc_stack;
3447 struct target_sigcontext tuc_mcontext;
3448 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003449};
3450
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003451/* Signal frames. */
3452struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003453 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003454 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3455 uint32_t tramp[2];
3456};
3457
3458struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003459 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003460 struct ucontext uc;
3461 uint32_t tramp[2];
3462};
3463
Andreas Färber05390242012-02-25 03:37:53 +01003464static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003465{
3466 __put_user(env->regs[0], &sc->regs.r0);
3467 __put_user(env->regs[1], &sc->regs.r1);
3468 __put_user(env->regs[2], &sc->regs.r2);
3469 __put_user(env->regs[3], &sc->regs.r3);
3470 __put_user(env->regs[4], &sc->regs.r4);
3471 __put_user(env->regs[5], &sc->regs.r5);
3472 __put_user(env->regs[6], &sc->regs.r6);
3473 __put_user(env->regs[7], &sc->regs.r7);
3474 __put_user(env->regs[8], &sc->regs.r8);
3475 __put_user(env->regs[9], &sc->regs.r9);
3476 __put_user(env->regs[10], &sc->regs.r10);
3477 __put_user(env->regs[11], &sc->regs.r11);
3478 __put_user(env->regs[12], &sc->regs.r12);
3479 __put_user(env->regs[13], &sc->regs.r13);
3480 __put_user(env->regs[14], &sc->regs.r14);
3481 __put_user(env->regs[15], &sc->regs.r15);
3482 __put_user(env->regs[16], &sc->regs.r16);
3483 __put_user(env->regs[17], &sc->regs.r17);
3484 __put_user(env->regs[18], &sc->regs.r18);
3485 __put_user(env->regs[19], &sc->regs.r19);
3486 __put_user(env->regs[20], &sc->regs.r20);
3487 __put_user(env->regs[21], &sc->regs.r21);
3488 __put_user(env->regs[22], &sc->regs.r22);
3489 __put_user(env->regs[23], &sc->regs.r23);
3490 __put_user(env->regs[24], &sc->regs.r24);
3491 __put_user(env->regs[25], &sc->regs.r25);
3492 __put_user(env->regs[26], &sc->regs.r26);
3493 __put_user(env->regs[27], &sc->regs.r27);
3494 __put_user(env->regs[28], &sc->regs.r28);
3495 __put_user(env->regs[29], &sc->regs.r29);
3496 __put_user(env->regs[30], &sc->regs.r30);
3497 __put_user(env->regs[31], &sc->regs.r31);
3498 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3499}
3500
Andreas Färber05390242012-02-25 03:37:53 +01003501static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003502{
3503 __get_user(env->regs[0], &sc->regs.r0);
3504 __get_user(env->regs[1], &sc->regs.r1);
3505 __get_user(env->regs[2], &sc->regs.r2);
3506 __get_user(env->regs[3], &sc->regs.r3);
3507 __get_user(env->regs[4], &sc->regs.r4);
3508 __get_user(env->regs[5], &sc->regs.r5);
3509 __get_user(env->regs[6], &sc->regs.r6);
3510 __get_user(env->regs[7], &sc->regs.r7);
3511 __get_user(env->regs[8], &sc->regs.r8);
3512 __get_user(env->regs[9], &sc->regs.r9);
3513 __get_user(env->regs[10], &sc->regs.r10);
3514 __get_user(env->regs[11], &sc->regs.r11);
3515 __get_user(env->regs[12], &sc->regs.r12);
3516 __get_user(env->regs[13], &sc->regs.r13);
3517 __get_user(env->regs[14], &sc->regs.r14);
3518 __get_user(env->regs[15], &sc->regs.r15);
3519 __get_user(env->regs[16], &sc->regs.r16);
3520 __get_user(env->regs[17], &sc->regs.r17);
3521 __get_user(env->regs[18], &sc->regs.r18);
3522 __get_user(env->regs[19], &sc->regs.r19);
3523 __get_user(env->regs[20], &sc->regs.r20);
3524 __get_user(env->regs[21], &sc->regs.r21);
3525 __get_user(env->regs[22], &sc->regs.r22);
3526 __get_user(env->regs[23], &sc->regs.r23);
3527 __get_user(env->regs[24], &sc->regs.r24);
3528 __get_user(env->regs[25], &sc->regs.r25);
3529 __get_user(env->regs[26], &sc->regs.r26);
3530 __get_user(env->regs[27], &sc->regs.r27);
3531 __get_user(env->regs[28], &sc->regs.r28);
3532 __get_user(env->regs[29], &sc->regs.r29);
3533 __get_user(env->regs[30], &sc->regs.r30);
3534 __get_user(env->regs[31], &sc->regs.r31);
3535 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3536}
3537
3538static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003539 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003540{
3541 abi_ulong sp = env->regs[1];
3542
3543 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3544 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3545
3546 return ((sp - frame_size) & -8UL);
3547}
3548
3549static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003550 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003551{
3552 struct target_signal_frame *frame;
3553 abi_ulong frame_addr;
3554 int err = 0;
3555 int i;
3556
3557 frame_addr = get_sigframe(ka, env, sizeof *frame);
3558 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3559 goto badframe;
3560
3561 /* Save the mask. */
Richard Hendersonf711df62010-11-22 14:57:52 -08003562 err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003563 if (err)
3564 goto badframe;
3565
3566 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3567 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3568 goto badframe;
3569 }
3570
Richard Hendersonf711df62010-11-22 14:57:52 -08003571 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003572
3573 /* Set up to return from userspace. If provided, use a stub
3574 already in userspace. */
3575 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3576 if (ka->sa_flags & TARGET_SA_RESTORER) {
3577 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3578 } else {
3579 uint32_t t;
3580 /* Note, these encodings are _big endian_! */
3581 /* addi r12, r0, __NR_sigreturn */
3582 t = 0x31800000UL | TARGET_NR_sigreturn;
3583 err |= __put_user(t, frame->tramp + 0);
3584 /* brki r14, 0x8 */
3585 t = 0xb9cc0008UL;
3586 err |= __put_user(t, frame->tramp + 1);
3587
3588 /* Return from sighandler will jump to the tramp.
3589 Negative 8 offset because return is rtsd r15, 8 */
3590 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3591 }
3592
3593 if (err)
3594 goto badframe;
3595
3596 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003597 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003598 /* Signal handler args: */
3599 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003600 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003601 /* arg 1: sigcontext */
3602 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003603
3604 /* Offset of 4 to handle microblaze rtid r14, 0 */
3605 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3606
3607 unlock_user_struct(frame, frame_addr, 1);
3608 return;
3609 badframe:
3610 unlock_user_struct(frame, frame_addr, 1);
3611 force_sig(TARGET_SIGSEGV);
3612}
3613
3614static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003615 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003616 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003617{
3618 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3619}
3620
Andreas Färber05390242012-02-25 03:37:53 +01003621long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003622{
3623 struct target_signal_frame *frame;
3624 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003625 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003626 sigset_t set;
3627 int i;
3628
3629 frame_addr = env->regs[R_SP];
3630 /* Make sure the guest isn't playing games. */
3631 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3632 goto badframe;
3633
3634 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003635 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003636 goto badframe;
3637 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3638 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3639 goto badframe;
3640 }
3641 target_to_host_sigset_internal(&set, &target_set);
3642 sigprocmask(SIG_SETMASK, &set, NULL);
3643
Richard Hendersonf711df62010-11-22 14:57:52 -08003644 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003645 /* We got here through a sigreturn syscall, our path back is via an
3646 rtb insn so setup r14 for that. */
3647 env->regs[14] = env->sregs[SR_PC];
3648
3649 unlock_user_struct(frame, frame_addr, 0);
3650 return env->regs[10];
3651 badframe:
3652 unlock_user_struct(frame, frame_addr, 0);
3653 force_sig(TARGET_SIGSEGV);
3654}
3655
Andreas Färber05390242012-02-25 03:37:53 +01003656long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003657{
3658 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3659 return -TARGET_ENOSYS;
3660}
3661
edgar_iglb6d3abd2008-02-28 11:29:27 +00003662#elif defined(TARGET_CRIS)
3663
3664struct target_sigcontext {
3665 struct target_pt_regs regs; /* needs to be first */
3666 uint32_t oldmask;
3667 uint32_t usp; /* usp before stacking this gunk on it */
3668};
3669
3670/* Signal frames. */
3671struct target_signal_frame {
3672 struct target_sigcontext sc;
3673 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003674 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003675};
3676
3677struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003678 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003679 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003680 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003681 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003682 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003683};
3684
Andreas Färber05390242012-02-25 03:37:53 +01003685static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003686{
edgar_igl9664d922008-03-03 22:23:53 +00003687 __put_user(env->regs[0], &sc->regs.r0);
3688 __put_user(env->regs[1], &sc->regs.r1);
3689 __put_user(env->regs[2], &sc->regs.r2);
3690 __put_user(env->regs[3], &sc->regs.r3);
3691 __put_user(env->regs[4], &sc->regs.r4);
3692 __put_user(env->regs[5], &sc->regs.r5);
3693 __put_user(env->regs[6], &sc->regs.r6);
3694 __put_user(env->regs[7], &sc->regs.r7);
3695 __put_user(env->regs[8], &sc->regs.r8);
3696 __put_user(env->regs[9], &sc->regs.r9);
3697 __put_user(env->regs[10], &sc->regs.r10);
3698 __put_user(env->regs[11], &sc->regs.r11);
3699 __put_user(env->regs[12], &sc->regs.r12);
3700 __put_user(env->regs[13], &sc->regs.r13);
3701 __put_user(env->regs[14], &sc->usp);
3702 __put_user(env->regs[15], &sc->regs.acr);
3703 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3704 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3705 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003706}
edgar_igl9664d922008-03-03 22:23:53 +00003707
Andreas Färber05390242012-02-25 03:37:53 +01003708static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003709{
edgar_igl9664d922008-03-03 22:23:53 +00003710 __get_user(env->regs[0], &sc->regs.r0);
3711 __get_user(env->regs[1], &sc->regs.r1);
3712 __get_user(env->regs[2], &sc->regs.r2);
3713 __get_user(env->regs[3], &sc->regs.r3);
3714 __get_user(env->regs[4], &sc->regs.r4);
3715 __get_user(env->regs[5], &sc->regs.r5);
3716 __get_user(env->regs[6], &sc->regs.r6);
3717 __get_user(env->regs[7], &sc->regs.r7);
3718 __get_user(env->regs[8], &sc->regs.r8);
3719 __get_user(env->regs[9], &sc->regs.r9);
3720 __get_user(env->regs[10], &sc->regs.r10);
3721 __get_user(env->regs[11], &sc->regs.r11);
3722 __get_user(env->regs[12], &sc->regs.r12);
3723 __get_user(env->regs[13], &sc->regs.r13);
3724 __get_user(env->regs[14], &sc->usp);
3725 __get_user(env->regs[15], &sc->regs.acr);
3726 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3727 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3728 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003729}
3730
Andreas Färber05390242012-02-25 03:37:53 +01003731static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003732{
edgar_igl9664d922008-03-03 22:23:53 +00003733 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003734 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003735 sp = (env->regs[R_SP] & ~3);
3736 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003737}
3738
pbrook624f7972008-05-31 16:11:38 +00003739static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003740 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003741{
3742 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003743 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003744 int err = 0;
3745 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003746
edgar_igl9664d922008-03-03 22:23:53 +00003747 frame_addr = get_sigframe(env, sizeof *frame);
3748 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003749 goto badframe;
3750
3751 /*
3752 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3753 * use this trampoline anymore but it sets it up for GDB.
3754 * In QEMU, using the trampoline simplifies things a bit so we use it.
3755 *
3756 * This is movu.w __NR_sigreturn, r9; break 13;
3757 */
3758 err |= __put_user(0x9c5f, frame->retcode+0);
3759 err |= __put_user(TARGET_NR_sigreturn,
Stefan Weil8cfc1142014-02-01 09:41:09 +01003760 frame->retcode + 1);
3761 err |= __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003762
3763 /* Save the mask. */
3764 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3765 if (err)
3766 goto badframe;
3767
3768 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3769 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3770 goto badframe;
3771 }
3772
3773 setup_sigcontext(&frame->sc, env);
3774
3775 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003776 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003777 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003778 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003779 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003780 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003781
edgar_igl9664d922008-03-03 22:23:53 +00003782 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003783 return;
3784 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003785 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003786 force_sig(TARGET_SIGSEGV);
3787}
3788
pbrook624f7972008-05-31 16:11:38 +00003789static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003790 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003791 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003792{
3793 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3794}
3795
Andreas Färber05390242012-02-25 03:37:53 +01003796long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003797{
3798 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003799 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003800 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003801 sigset_t set;
3802 int i;
3803
edgar_igl9664d922008-03-03 22:23:53 +00003804 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003805 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003806 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003807 goto badframe;
3808
3809 /* Restore blocked signals */
3810 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3811 goto badframe;
3812 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3813 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3814 goto badframe;
3815 }
3816 target_to_host_sigset_internal(&set, &target_set);
3817 sigprocmask(SIG_SETMASK, &set, NULL);
3818
3819 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003820 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003821 return env->regs[10];
3822 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003823 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003824 force_sig(TARGET_SIGSEGV);
3825}
3826
Andreas Färber05390242012-02-25 03:37:53 +01003827long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003828{
3829 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3830 return -TARGET_ENOSYS;
3831}
thsc3b5bc82007-12-02 06:31:25 +00003832
Jia Liud9627832012-07-20 15:50:52 +08003833#elif defined(TARGET_OPENRISC)
3834
3835struct target_sigcontext {
3836 struct target_pt_regs regs;
3837 abi_ulong oldmask;
3838 abi_ulong usp;
3839};
3840
3841struct target_ucontext {
3842 abi_ulong tuc_flags;
3843 abi_ulong tuc_link;
3844 target_stack_t tuc_stack;
3845 struct target_sigcontext tuc_mcontext;
3846 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3847};
3848
3849struct target_rt_sigframe {
3850 abi_ulong pinfo;
3851 uint64_t puc;
3852 struct target_siginfo info;
3853 struct target_sigcontext sc;
3854 struct target_ucontext uc;
3855 unsigned char retcode[16]; /* trampoline code */
3856};
3857
3858/* This is the asm-generic/ucontext.h version */
3859#if 0
3860static int restore_sigcontext(CPUOpenRISCState *regs,
3861 struct target_sigcontext *sc)
3862{
3863 unsigned int err = 0;
3864 unsigned long old_usp;
3865
3866 /* Alwys make any pending restarted system call return -EINTR */
3867 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3868
3869 /* restore the regs from &sc->regs (same as sc, since regs is first)
3870 * (sc is already checked for VERIFY_READ since the sigframe was
3871 * checked in sys_sigreturn previously)
3872 */
3873
3874 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3875 goto badframe;
3876 }
3877
3878 /* make sure the U-flag is set so user-mode cannot fool us */
3879
3880 regs->sr &= ~SR_SM;
3881
3882 /* restore the old USP as it was before we stacked the sc etc.
3883 * (we cannot just pop the sigcontext since we aligned the sp and
3884 * stuff after pushing it)
3885 */
3886
3887 err |= __get_user(old_usp, &sc->usp);
3888 phx_signal("old_usp 0x%lx", old_usp);
3889
3890 __PHX__ REALLY /* ??? */
3891 wrusp(old_usp);
3892 regs->gpr[1] = old_usp;
3893
3894 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3895 * after this completes, but we don't use that mechanism. maybe we can
3896 * use it now ?
3897 */
3898
3899 return err;
3900
3901badframe:
3902 return 1;
3903}
3904#endif
3905
3906/* Set up a signal frame. */
3907
3908static int setup_sigcontext(struct target_sigcontext *sc,
3909 CPUOpenRISCState *regs,
3910 unsigned long mask)
3911{
3912 int err = 0;
3913 unsigned long usp = regs->gpr[1];
3914
3915 /* copy the regs. they are first in sc so we can use sc directly */
3916
3917 /*err |= copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
3918
3919 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3920 the signal handler. The frametype will be restored to its previous
3921 value in restore_sigcontext. */
3922 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3923
3924 /* then some other stuff */
3925 err |= __put_user(mask, &sc->oldmask);
3926 err |= __put_user(usp, &sc->usp); return err;
3927}
3928
3929static inline unsigned long align_sigframe(unsigned long sp)
3930{
3931 unsigned long i;
3932 i = sp & ~3UL;
3933 return i;
3934}
3935
3936static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3937 CPUOpenRISCState *regs,
3938 size_t frame_size)
3939{
3940 unsigned long sp = regs->gpr[1];
3941 int onsigstack = on_sig_stack(sp);
3942
3943 /* redzone */
3944 /* This is the X/Open sanctioned signal stack switching. */
3945 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3946 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3947 }
3948
3949 sp = align_sigframe(sp - frame_size);
3950
3951 /*
3952 * If we are on the alternate signal stack and would overflow it, don't.
3953 * Return an always-bogus address instead so we will die with SIGSEGV.
3954 */
3955
3956 if (onsigstack && !likely(on_sig_stack(sp))) {
3957 return -1L;
3958 }
3959
3960 return sp;
3961}
3962
3963static void setup_frame(int sig, struct target_sigaction *ka,
3964 target_sigset_t *set, CPUOpenRISCState *env)
3965{
3966 qemu_log("Not implement.\n");
3967}
3968
3969static void setup_rt_frame(int sig, struct target_sigaction *ka,
3970 target_siginfo_t *info,
3971 target_sigset_t *set, CPUOpenRISCState *env)
3972{
3973 int err = 0;
3974 abi_ulong frame_addr;
3975 unsigned long return_ip;
3976 struct target_rt_sigframe *frame;
3977 abi_ulong info_addr, uc_addr;
3978
3979 frame_addr = get_sigframe(ka, env, sizeof *frame);
3980
3981 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3982 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3983 goto give_sigsegv;
3984 }
3985
3986 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
3987 err |= __put_user(info_addr, &frame->pinfo);
3988 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
3989 err |= __put_user(uc_addr, &frame->puc);
3990
3991 if (ka->sa_flags & SA_SIGINFO) {
3992 err |= copy_siginfo_to_user(&frame->info, info);
3993 }
3994 if (err) {
3995 goto give_sigsegv;
3996 }
3997
3998 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
3999 err |= __put_user(0, &frame->uc.tuc_flags);
4000 err |= __put_user(0, &frame->uc.tuc_link);
4001 err |= __put_user(target_sigaltstack_used.ss_sp,
4002 &frame->uc.tuc_stack.ss_sp);
4003 err |= __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
4004 err |= __put_user(target_sigaltstack_used.ss_size,
4005 &frame->uc.tuc_stack.ss_size);
4006 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
4007
4008 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4009
4010 if (err) {
4011 goto give_sigsegv;
4012 }
4013
4014 /* trampoline - the desired return ip is the retcode itself */
4015 return_ip = (unsigned long)&frame->retcode;
4016 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
4017 err |= __put_user(0xa960, (short *)(frame->retcode + 0));
4018 err |= __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4019 err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4020 err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
4021
4022 if (err) {
4023 goto give_sigsegv;
4024 }
4025
4026 /* TODO what is the current->exec_domain stuff and invmap ? */
4027
4028 /* Set up registers for signal handler */
4029 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4030 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4031 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4032 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4033 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4034
4035 /* actually move the usp to reflect the stacked frame */
4036 env->gpr[1] = (unsigned long)frame;
4037
4038 return;
4039
4040give_sigsegv:
4041 unlock_user_struct(frame, frame_addr, 1);
4042 if (sig == TARGET_SIGSEGV) {
4043 ka->_sa_handler = TARGET_SIG_DFL;
4044 }
4045 force_sig(TARGET_SIGSEGV);
4046}
4047
4048long do_sigreturn(CPUOpenRISCState *env)
4049{
4050
4051 qemu_log("do_sigreturn: not implemented\n");
4052 return -TARGET_ENOSYS;
4053}
4054
4055long do_rt_sigreturn(CPUOpenRISCState *env)
4056{
4057 qemu_log("do_rt_sigreturn: not implemented\n");
4058 return -TARGET_ENOSYS;
4059}
4060/* TARGET_OPENRISC */
4061
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004062#elif defined(TARGET_S390X)
4063
4064#define __NUM_GPRS 16
4065#define __NUM_FPRS 16
4066#define __NUM_ACRS 16
4067
4068#define S390_SYSCALL_SIZE 2
4069#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4070
4071#define _SIGCONTEXT_NSIG 64
4072#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4073#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4074#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4075#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4076#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4077
4078typedef struct {
4079 target_psw_t psw;
4080 target_ulong gprs[__NUM_GPRS];
4081 unsigned int acrs[__NUM_ACRS];
4082} target_s390_regs_common;
4083
4084typedef struct {
4085 unsigned int fpc;
4086 double fprs[__NUM_FPRS];
4087} target_s390_fp_regs;
4088
4089typedef struct {
4090 target_s390_regs_common regs;
4091 target_s390_fp_regs fpregs;
4092} target_sigregs;
4093
4094struct target_sigcontext {
4095 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4096 target_sigregs *sregs;
4097};
4098
4099typedef struct {
4100 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4101 struct target_sigcontext sc;
4102 target_sigregs sregs;
4103 int signo;
4104 uint8_t retcode[S390_SYSCALL_SIZE];
4105} sigframe;
4106
4107struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004108 target_ulong tuc_flags;
4109 struct target_ucontext *tuc_link;
4110 target_stack_t tuc_stack;
4111 target_sigregs tuc_mcontext;
4112 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004113};
4114
4115typedef struct {
4116 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4117 uint8_t retcode[S390_SYSCALL_SIZE];
4118 struct target_siginfo info;
4119 struct target_ucontext uc;
4120} rt_sigframe;
4121
4122static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004123get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004124{
4125 abi_ulong sp;
4126
4127 /* Default to using normal stack */
4128 sp = env->regs[15];
4129
4130 /* This is the X/Open sanctioned signal stack switching. */
4131 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4132 if (!sas_ss_flags(sp)) {
4133 sp = target_sigaltstack_used.ss_sp +
4134 target_sigaltstack_used.ss_size;
4135 }
4136 }
4137
4138 /* This is the legacy signal stack switching. */
4139 else if (/* FIXME !user_mode(regs) */ 0 &&
4140 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4141 ka->sa_restorer) {
4142 sp = (abi_ulong) ka->sa_restorer;
4143 }
4144
4145 return (sp - frame_size) & -8ul;
4146}
4147
Andreas Färber05390242012-02-25 03:37:53 +01004148static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004149{
4150 int i;
4151 //save_access_regs(current->thread.acrs); FIXME
4152
4153 /* Copy a 'clean' PSW mask to the user to avoid leaking
4154 information about whether PER is currently on. */
4155 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4156 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4157 for (i = 0; i < 16; i++) {
4158 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4159 }
4160 for (i = 0; i < 16; i++) {
4161 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4162 }
4163 /*
4164 * We have to store the fp registers to current->thread.fp_regs
4165 * to merge them with the emulated registers.
4166 */
4167 //save_fp_regs(&current->thread.fp_regs); FIXME
4168 for (i = 0; i < 16; i++) {
4169 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4170 }
4171}
4172
4173static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004174 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004175{
4176 sigframe *frame;
4177 abi_ulong frame_addr;
4178
4179 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4180 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4181 (unsigned long long)frame_addr);
4182 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4183 goto give_sigsegv;
4184 }
4185
4186 qemu_log("%s: 1\n", __FUNCTION__);
4187 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
4188 goto give_sigsegv;
4189 }
4190
4191 save_sigregs(env, &frame->sregs);
4192
4193 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4194 (abi_ulong *)&frame->sc.sregs);
4195
4196 /* Set up to return from userspace. If provided, use a stub
4197 already in userspace. */
4198 if (ka->sa_flags & TARGET_SA_RESTORER) {
4199 env->regs[14] = (unsigned long)
4200 ka->sa_restorer | PSW_ADDR_AMODE;
4201 } else {
4202 env->regs[14] = (unsigned long)
4203 frame->retcode | PSW_ADDR_AMODE;
4204 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4205 (uint16_t *)(frame->retcode)))
4206 goto give_sigsegv;
4207 }
4208
4209 /* Set up backchain. */
4210 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4211 goto give_sigsegv;
4212 }
4213
4214 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004215 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004216 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4217
4218 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004219 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004220
4221 /* We forgot to include these in the sigcontext.
4222 To avoid breaking binary compatibility, they are passed as args. */
4223 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4224 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4225
4226 /* Place signal number on stack to allow backtrace from handler. */
4227 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4228 goto give_sigsegv;
4229 }
4230 unlock_user_struct(frame, frame_addr, 1);
4231 return;
4232
4233give_sigsegv:
4234 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4235 unlock_user_struct(frame, frame_addr, 1);
4236 force_sig(TARGET_SIGSEGV);
4237}
4238
4239static void setup_rt_frame(int sig, struct target_sigaction *ka,
4240 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004241 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004242{
4243 int i;
4244 rt_sigframe *frame;
4245 abi_ulong frame_addr;
4246
4247 frame_addr = get_sigframe(ka, env, sizeof *frame);
4248 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4249 (unsigned long long)frame_addr);
4250 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4251 goto give_sigsegv;
4252 }
4253
4254 qemu_log("%s: 1\n", __FUNCTION__);
4255 if (copy_siginfo_to_user(&frame->info, info)) {
4256 goto give_sigsegv;
4257 }
4258
4259 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004260 __put_user(0, &frame->uc.tuc_flags);
4261 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4262 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004263 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004264 &frame->uc.tuc_stack.ss_flags);
4265 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4266 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004267 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4268 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004269 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004270 }
4271
4272 /* Set up to return from userspace. If provided, use a stub
4273 already in userspace. */
4274 if (ka->sa_flags & TARGET_SA_RESTORER) {
4275 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4276 } else {
4277 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4278 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4279 (uint16_t *)(frame->retcode))) {
4280 goto give_sigsegv;
4281 }
4282 }
4283
4284 /* Set up backchain. */
4285 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4286 goto give_sigsegv;
4287 }
4288
4289 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004290 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004291 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4292
4293 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004294 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4295 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004296 return;
4297
4298give_sigsegv:
4299 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4300 unlock_user_struct(frame, frame_addr, 1);
4301 force_sig(TARGET_SIGSEGV);
4302}
4303
4304static int
Andreas Färber05390242012-02-25 03:37:53 +01004305restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004306{
4307 int err = 0;
4308 int i;
4309
4310 for (i = 0; i < 16; i++) {
4311 err |= __get_user(env->regs[i], &sc->regs.gprs[i]);
4312 }
4313
4314 err |= __get_user(env->psw.mask, &sc->regs.psw.mask);
4315 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4316 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4317 (unsigned long long)env->psw.addr);
4318 err |= __get_user(env->psw.addr, &sc->regs.psw.addr);
4319 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4320
4321 for (i = 0; i < 16; i++) {
4322 err |= __get_user(env->aregs[i], &sc->regs.acrs[i]);
4323 }
4324 for (i = 0; i < 16; i++) {
4325 err |= __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
4326 }
4327
4328 return err;
4329}
4330
Andreas Färber05390242012-02-25 03:37:53 +01004331long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004332{
4333 sigframe *frame;
4334 abi_ulong frame_addr = env->regs[15];
4335 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4336 (unsigned long long)frame_addr);
4337 target_sigset_t target_set;
4338 sigset_t set;
4339
4340 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4341 goto badframe;
4342 }
4343 if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
4344 goto badframe;
4345 }
4346
4347 target_to_host_sigset_internal(&set, &target_set);
4348 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4349
4350 if (restore_sigregs(env, &frame->sregs)) {
4351 goto badframe;
4352 }
4353
4354 unlock_user_struct(frame, frame_addr, 0);
4355 return env->regs[2];
4356
4357badframe:
4358 unlock_user_struct(frame, frame_addr, 0);
4359 force_sig(TARGET_SIGSEGV);
4360 return 0;
4361}
4362
Andreas Färber05390242012-02-25 03:37:53 +01004363long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004364{
4365 rt_sigframe *frame;
4366 abi_ulong frame_addr = env->regs[15];
4367 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4368 (unsigned long long)frame_addr);
4369 sigset_t set;
4370
4371 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4372 goto badframe;
4373 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004374 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004375
4376 sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
4377
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004378 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004379 goto badframe;
4380 }
4381
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004382 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004383 get_sp_from_cpustate(env)) == -EFAULT) {
4384 goto badframe;
4385 }
4386 unlock_user_struct(frame, frame_addr, 0);
4387 return env->regs[2];
4388
4389badframe:
4390 unlock_user_struct(frame, frame_addr, 0);
4391 force_sig(TARGET_SIGSEGV);
4392 return 0;
4393}
4394
Nathan Froydbcd49332009-05-12 19:13:18 -07004395#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4396
4397/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4398 the signal handling is different enough that we haven't implemented
4399 support for PPC64 yet. Hence the restriction above.
4400
4401 There are various #if'd blocks for code for TARGET_PPC64. These
4402 blocks should go away so that we can successfully run 32-bit and
4403 64-bit binaries on a QEMU configured for PPC64. */
4404
4405/* Size of dummy stack frame allocated when calling signal handler.
4406 See arch/powerpc/include/asm/ptrace.h. */
4407#if defined(TARGET_PPC64)
4408#define SIGNAL_FRAMESIZE 128
4409#else
4410#define SIGNAL_FRAMESIZE 64
4411#endif
4412
4413/* See arch/powerpc/include/asm/sigcontext.h. */
4414struct target_sigcontext {
4415 target_ulong _unused[4];
4416 int32_t signal;
4417#if defined(TARGET_PPC64)
4418 int32_t pad0;
4419#endif
4420 target_ulong handler;
4421 target_ulong oldmask;
4422 target_ulong regs; /* struct pt_regs __user * */
4423 /* TODO: PPC64 includes extra bits here. */
4424};
4425
4426/* Indices for target_mcontext.mc_gregs, below.
4427 See arch/powerpc/include/asm/ptrace.h for details. */
4428enum {
4429 TARGET_PT_R0 = 0,
4430 TARGET_PT_R1 = 1,
4431 TARGET_PT_R2 = 2,
4432 TARGET_PT_R3 = 3,
4433 TARGET_PT_R4 = 4,
4434 TARGET_PT_R5 = 5,
4435 TARGET_PT_R6 = 6,
4436 TARGET_PT_R7 = 7,
4437 TARGET_PT_R8 = 8,
4438 TARGET_PT_R9 = 9,
4439 TARGET_PT_R10 = 10,
4440 TARGET_PT_R11 = 11,
4441 TARGET_PT_R12 = 12,
4442 TARGET_PT_R13 = 13,
4443 TARGET_PT_R14 = 14,
4444 TARGET_PT_R15 = 15,
4445 TARGET_PT_R16 = 16,
4446 TARGET_PT_R17 = 17,
4447 TARGET_PT_R18 = 18,
4448 TARGET_PT_R19 = 19,
4449 TARGET_PT_R20 = 20,
4450 TARGET_PT_R21 = 21,
4451 TARGET_PT_R22 = 22,
4452 TARGET_PT_R23 = 23,
4453 TARGET_PT_R24 = 24,
4454 TARGET_PT_R25 = 25,
4455 TARGET_PT_R26 = 26,
4456 TARGET_PT_R27 = 27,
4457 TARGET_PT_R28 = 28,
4458 TARGET_PT_R29 = 29,
4459 TARGET_PT_R30 = 30,
4460 TARGET_PT_R31 = 31,
4461 TARGET_PT_NIP = 32,
4462 TARGET_PT_MSR = 33,
4463 TARGET_PT_ORIG_R3 = 34,
4464 TARGET_PT_CTR = 35,
4465 TARGET_PT_LNK = 36,
4466 TARGET_PT_XER = 37,
4467 TARGET_PT_CCR = 38,
4468 /* Yes, there are two registers with #39. One is 64-bit only. */
4469 TARGET_PT_MQ = 39,
4470 TARGET_PT_SOFTE = 39,
4471 TARGET_PT_TRAP = 40,
4472 TARGET_PT_DAR = 41,
4473 TARGET_PT_DSISR = 42,
4474 TARGET_PT_RESULT = 43,
4475 TARGET_PT_REGS_COUNT = 44
4476};
4477
4478/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4479 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4480struct target_mcontext {
4481 target_ulong mc_gregs[48];
4482 /* Includes fpscr. */
4483 uint64_t mc_fregs[33];
4484 target_ulong mc_pad[2];
4485 /* We need to handle Altivec and SPE at the same time, which no
4486 kernel needs to do. Fortunately, the kernel defines this bit to
4487 be Altivec-register-large all the time, rather than trying to
4488 twiddle it based on the specific platform. */
4489 union {
4490 /* SPE vector registers. One extra for SPEFSCR. */
4491 uint32_t spe[33];
4492 /* Altivec vector registers. The packing of VSCR and VRSAVE
4493 varies depending on whether we're PPC64 or not: PPC64 splits
4494 them apart; PPC32 stuffs them together. */
4495#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004496#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004497#else
malc3efa9a62009-07-18 13:10:12 +04004498#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004499#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004500 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004501#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004502 } mc_vregs __attribute__((__aligned__(16)));
4503};
4504
4505struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004506 target_ulong tuc_flags;
4507 target_ulong tuc_link; /* struct ucontext __user * */
4508 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004509#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004510 int32_t tuc_pad[7];
4511 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004512 points to uc_mcontext field */
4513#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004514 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004515#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004516 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004517 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004518#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004519 int32_t tuc_maskext[30];
4520 int32_t tuc_pad2[3];
4521 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004522#endif
4523};
4524
4525/* See arch/powerpc/kernel/signal_32.c. */
4526struct target_sigframe {
4527 struct target_sigcontext sctx;
4528 struct target_mcontext mctx;
4529 int32_t abigap[56];
4530};
4531
4532struct target_rt_sigframe {
4533 struct target_siginfo info;
4534 struct target_ucontext uc;
4535 int32_t abigap[56];
4536};
4537
4538/* We use the mc_pad field for the signal return trampoline. */
4539#define tramp mc_pad
4540
4541/* See arch/powerpc/kernel/signal.c. */
4542static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004543 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004544 int frame_size)
4545{
4546 target_ulong oldsp, newsp;
4547
4548 oldsp = env->gpr[1];
4549
4550 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004551 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004552 oldsp = (target_sigaltstack_used.ss_sp
4553 + target_sigaltstack_used.ss_size);
4554 }
4555
4556 newsp = (oldsp - frame_size) & ~0xFUL;
4557
4558 return newsp;
4559}
4560
Andreas Färber05390242012-02-25 03:37:53 +01004561static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004562 int sigret)
4563{
4564 target_ulong msr = env->msr;
4565 int i;
4566 target_ulong ccr = 0;
4567
4568 /* In general, the kernel attempts to be intelligent about what it
4569 needs to save for Altivec/FP/SPE registers. We don't care that
4570 much, so we just go ahead and save everything. */
4571
4572 /* Save general registers. */
4573 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4574 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4575 return 1;
4576 }
4577 }
4578 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4579 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4580 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4581 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4582 return 1;
4583
4584 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4585 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4586 }
4587 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4588 return 1;
4589
4590 /* Save Altivec registers if necessary. */
4591 if (env->insns_flags & PPC_ALTIVEC) {
4592 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004593 ppc_avr_t *avr = &env->avr[i];
4594 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004595
4596 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4597 __put_user(avr->u64[1], &vreg->u64[1])) {
4598 return 1;
4599 }
4600 }
4601 /* Set MSR_VR in the saved MSR value to indicate that
4602 frame->mc_vregs contains valid data. */
4603 msr |= MSR_VR;
4604 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4605 &frame->mc_vregs.altivec[32].u32[3]))
4606 return 1;
4607 }
4608
4609 /* Save floating point registers. */
4610 if (env->insns_flags & PPC_FLOAT) {
4611 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4612 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4613 return 1;
4614 }
4615 }
4616 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4617 return 1;
4618 }
4619
4620 /* Save SPE registers. The kernel only saves the high half. */
4621 if (env->insns_flags & PPC_SPE) {
4622#if defined(TARGET_PPC64)
4623 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4624 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4625 return 1;
4626 }
4627 }
4628#else
4629 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4630 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4631 return 1;
4632 }
4633 }
4634#endif
4635 /* Set MSR_SPE in the saved MSR value to indicate that
4636 frame->mc_vregs contains valid data. */
4637 msr |= MSR_SPE;
4638 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4639 return 1;
4640 }
4641
4642 /* Store MSR. */
4643 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4644 return 1;
4645
4646 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4647 if (sigret) {
4648 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4649 __put_user(0x44000002UL, &frame->tramp[1])) {
4650 return 1;
4651 }
4652 }
4653
4654 return 0;
4655}
4656
Andreas Färber05390242012-02-25 03:37:53 +01004657static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004658 struct target_mcontext *frame, int sig)
4659{
4660 target_ulong save_r2 = 0;
4661 target_ulong msr;
4662 target_ulong ccr;
4663
4664 int i;
4665
4666 if (!sig) {
4667 save_r2 = env->gpr[2];
4668 }
4669
4670 /* Restore general registers. */
4671 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4672 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4673 return 1;
4674 }
4675 }
4676 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4677 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4678 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4679 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4680 return 1;
4681 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4682 return 1;
4683
4684 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4685 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4686 }
4687
4688 if (!sig) {
4689 env->gpr[2] = save_r2;
4690 }
4691 /* Restore MSR. */
4692 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4693 return 1;
4694
4695 /* If doing signal return, restore the previous little-endian mode. */
4696 if (sig)
4697 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4698
4699 /* Restore Altivec registers if necessary. */
4700 if (env->insns_flags & PPC_ALTIVEC) {
4701 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004702 ppc_avr_t *avr = &env->avr[i];
4703 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004704
4705 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4706 __get_user(avr->u64[1], &vreg->u64[1])) {
4707 return 1;
4708 }
4709 }
4710 /* Set MSR_VEC in the saved MSR value to indicate that
4711 frame->mc_vregs contains valid data. */
4712 if (__get_user(env->spr[SPR_VRSAVE],
4713 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4714 return 1;
4715 }
4716
4717 /* Restore floating point registers. */
4718 if (env->insns_flags & PPC_FLOAT) {
4719 uint64_t fpscr;
4720 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4721 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4722 return 1;
4723 }
4724 }
4725 if (__get_user(fpscr, &frame->mc_fregs[32]))
4726 return 1;
4727 env->fpscr = (uint32_t) fpscr;
4728 }
4729
4730 /* Save SPE registers. The kernel only saves the high half. */
4731 if (env->insns_flags & PPC_SPE) {
4732#if defined(TARGET_PPC64)
4733 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4734 uint32_t hi;
4735
4736 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4737 return 1;
4738 }
4739 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4740 }
4741#else
4742 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4743 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4744 return 1;
4745 }
4746 }
4747#endif
4748 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4749 return 1;
4750 }
4751
4752 return 0;
4753}
4754
4755static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004756 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004757{
4758 struct target_sigframe *frame;
4759 struct target_sigcontext *sc;
4760 target_ulong frame_addr, newsp;
4761 int err = 0;
4762 int signal;
4763
4764 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4765 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4766 goto sigsegv;
4767 sc = &frame->sctx;
4768
4769 signal = current_exec_domain_sig(sig);
4770
Samuel Seaybeb526b2013-01-02 10:53:46 +00004771 err |= __put_user(ka->_sa_handler, &sc->handler);
Nathan Froydbcd49332009-05-12 19:13:18 -07004772 err |= __put_user(set->sig[0], &sc->oldmask);
4773#if defined(TARGET_PPC64)
4774 err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
4775#else
4776 err |= __put_user(set->sig[1], &sc->_unused[3]);
4777#endif
4778 err |= __put_user(h2g(&frame->mctx), &sc->regs);
4779 err |= __put_user(sig, &sc->signal);
4780
4781 /* Save user regs. */
4782 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4783
4784 /* The kernel checks for the presence of a VDSO here. We don't
4785 emulate a vdso, so use a sigreturn system call. */
4786 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4787
4788 /* Turn off all fp exceptions. */
4789 env->fpscr = 0;
4790
4791 /* Create a stack frame for the caller of the handler. */
4792 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004793 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004794
4795 if (err)
4796 goto sigsegv;
4797
4798 /* Set up registers for signal handler. */
4799 env->gpr[1] = newsp;
4800 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004801 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004802 env->nip = (target_ulong) ka->_sa_handler;
4803 /* Signal handlers are entered in big-endian mode. */
4804 env->msr &= ~MSR_LE;
4805
4806 unlock_user_struct(frame, frame_addr, 1);
4807 return;
4808
4809sigsegv:
4810 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004811 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004812 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004813}
4814
4815static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004816 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004817 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004818{
4819 struct target_rt_sigframe *rt_sf;
4820 struct target_mcontext *frame;
4821 target_ulong rt_sf_addr, newsp = 0;
4822 int i, err = 0;
4823 int signal;
4824
4825 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4826 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4827 goto sigsegv;
4828
4829 signal = current_exec_domain_sig(sig);
4830
4831 err |= copy_siginfo_to_user(&rt_sf->info, info);
4832
Aurelien Jarno60e99242010-03-29 02:12:51 +02004833 err |= __put_user(0, &rt_sf->uc.tuc_flags);
4834 err |= __put_user(0, &rt_sf->uc.tuc_link);
Nathan Froydbcd49332009-05-12 19:13:18 -07004835 err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004836 &rt_sf->uc.tuc_stack.ss_sp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004837 err |= __put_user(sas_ss_flags(env->gpr[1]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02004838 &rt_sf->uc.tuc_stack.ss_flags);
Nathan Froydbcd49332009-05-12 19:13:18 -07004839 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004840 &rt_sf->uc.tuc_stack.ss_size);
4841 err |= __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4842 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004843 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004844 err |= __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004845 }
4846
Aurelien Jarno60e99242010-03-29 02:12:51 +02004847 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004848 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4849
4850 /* The kernel checks for the presence of a VDSO here. We don't
4851 emulate a vdso, so use a sigreturn system call. */
4852 env->lr = (target_ulong) h2g(frame->tramp);
4853
4854 /* Turn off all fp exceptions. */
4855 env->fpscr = 0;
4856
4857 /* Create a stack frame for the caller of the handler. */
4858 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
4859 err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
4860
4861 if (err)
4862 goto sigsegv;
4863
4864 /* Set up registers for signal handler. */
4865 env->gpr[1] = newsp;
4866 env->gpr[3] = (target_ulong) signal;
4867 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4868 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4869 env->gpr[6] = (target_ulong) h2g(rt_sf);
4870 env->nip = (target_ulong) ka->_sa_handler;
4871 /* Signal handlers are entered in big-endian mode. */
4872 env->msr &= ~MSR_LE;
4873
4874 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4875 return;
4876
4877sigsegv:
4878 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004879 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004880 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004881
4882}
4883
Andreas Färber05390242012-02-25 03:37:53 +01004884long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004885{
4886 struct target_sigcontext *sc = NULL;
4887 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004888 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004889 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004890 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004891
4892 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4893 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4894 goto sigsegv;
4895
4896#if defined(TARGET_PPC64)
4897 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4898#else
4899 if(__get_user(set.sig[0], &sc->oldmask) ||
4900 __get_user(set.sig[1], &sc->_unused[3]))
4901 goto sigsegv;
4902#endif
4903 target_to_host_sigset_internal(&blocked, &set);
4904 sigprocmask(SIG_SETMASK, &blocked, NULL);
4905
4906 if (__get_user(sr_addr, &sc->regs))
4907 goto sigsegv;
4908 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4909 goto sigsegv;
4910 if (restore_user_regs(env, sr, 1))
4911 goto sigsegv;
4912
4913 unlock_user_struct(sr, sr_addr, 1);
4914 unlock_user_struct(sc, sc_addr, 1);
4915 return -TARGET_QEMU_ESIGRETURN;
4916
4917sigsegv:
4918 unlock_user_struct(sr, sr_addr, 1);
4919 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004920 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004921 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004922 return 0;
4923}
4924
4925/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004926static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004927{
4928 struct target_mcontext *mcp;
4929 target_ulong mcp_addr;
4930 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004931 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004932
Aurelien Jarno60e99242010-03-29 02:12:51 +02004933 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004934 sizeof (set)))
4935 return 1;
4936
4937#if defined(TARGET_PPC64)
4938 fprintf (stderr, "do_setcontext: not implemented\n");
4939 return 0;
4940#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004941 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004942 return 1;
4943
4944 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4945 return 1;
4946
4947 target_to_host_sigset_internal(&blocked, &set);
4948 sigprocmask(SIG_SETMASK, &blocked, NULL);
4949 if (restore_user_regs(env, mcp, sig))
4950 goto sigsegv;
4951
4952 unlock_user_struct(mcp, mcp_addr, 1);
4953 return 0;
4954
4955sigsegv:
4956 unlock_user_struct(mcp, mcp_addr, 1);
4957 return 1;
4958#endif
4959}
4960
Andreas Färber05390242012-02-25 03:37:53 +01004961long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004962{
4963 struct target_rt_sigframe *rt_sf = NULL;
4964 target_ulong rt_sf_addr;
4965
4966 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4967 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4968 goto sigsegv;
4969
4970 if (do_setcontext(&rt_sf->uc, env, 1))
4971 goto sigsegv;
4972
4973 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004974 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004975 0, env->gpr[1]);
4976
4977 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4978 return -TARGET_QEMU_ESIGRETURN;
4979
4980sigsegv:
4981 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004982 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004983 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004984 return 0;
4985}
4986
Laurent Vivier492a8742009-08-03 16:12:17 +02004987#elif defined(TARGET_M68K)
4988
4989struct target_sigcontext {
4990 abi_ulong sc_mask;
4991 abi_ulong sc_usp;
4992 abi_ulong sc_d0;
4993 abi_ulong sc_d1;
4994 abi_ulong sc_a0;
4995 abi_ulong sc_a1;
4996 unsigned short sc_sr;
4997 abi_ulong sc_pc;
4998};
4999
5000struct target_sigframe
5001{
5002 abi_ulong pretcode;
5003 int sig;
5004 int code;
5005 abi_ulong psc;
5006 char retcode[8];
5007 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5008 struct target_sigcontext sc;
5009};
Laurent Vivier71811552009-08-03 16:12:18 +02005010
Anthony Liguoric227f092009-10-01 16:12:16 -05005011typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005012#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005013typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005014
5015typedef struct target_fpregset {
5016 int f_fpcntl[3];
5017 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005018} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005019
5020struct target_mcontext {
5021 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005022 target_gregset_t gregs;
5023 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005024};
5025
5026#define TARGET_MCONTEXT_VERSION 2
5027
5028struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005029 abi_ulong tuc_flags;
5030 abi_ulong tuc_link;
5031 target_stack_t tuc_stack;
5032 struct target_mcontext tuc_mcontext;
5033 abi_long tuc_filler[80];
5034 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005035};
5036
5037struct target_rt_sigframe
5038{
5039 abi_ulong pretcode;
5040 int sig;
5041 abi_ulong pinfo;
5042 abi_ulong puc;
5043 char retcode[8];
5044 struct target_siginfo info;
5045 struct target_ucontext uc;
5046};
Laurent Vivier492a8742009-08-03 16:12:17 +02005047
5048static int
Andreas Färber05390242012-02-25 03:37:53 +01005049setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
5050 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005051{
5052 int err = 0;
5053
5054 err |= __put_user(mask, &sc->sc_mask);
5055 err |= __put_user(env->aregs[7], &sc->sc_usp);
5056 err |= __put_user(env->dregs[0], &sc->sc_d0);
5057 err |= __put_user(env->dregs[1], &sc->sc_d1);
5058 err |= __put_user(env->aregs[0], &sc->sc_a0);
5059 err |= __put_user(env->aregs[1], &sc->sc_a1);
5060 err |= __put_user(env->sr, &sc->sc_sr);
5061 err |= __put_user(env->pc, &sc->sc_pc);
5062
5063 return err;
5064}
5065
5066static int
Andreas Färber05390242012-02-25 03:37:53 +01005067restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005068{
5069 int err = 0;
5070 int temp;
5071
5072 err |= __get_user(env->aregs[7], &sc->sc_usp);
5073 err |= __get_user(env->dregs[1], &sc->sc_d1);
5074 err |= __get_user(env->aregs[0], &sc->sc_a0);
5075 err |= __get_user(env->aregs[1], &sc->sc_a1);
5076 err |= __get_user(env->pc, &sc->sc_pc);
5077 err |= __get_user(temp, &sc->sc_sr);
5078 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5079
5080 *pd0 = tswapl(sc->sc_d0);
5081
5082 return err;
5083}
5084
5085/*
5086 * Determine which stack to use..
5087 */
5088static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005089get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5090 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005091{
5092 unsigned long sp;
5093
5094 sp = regs->aregs[7];
5095
5096 /* This is the X/Open sanctioned signal stack switching. */
5097 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5098 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5099 }
5100
5101 return ((sp - frame_size) & -8UL);
5102}
5103
5104static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005105 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005106{
5107 struct target_sigframe *frame;
5108 abi_ulong frame_addr;
5109 abi_ulong retcode_addr;
5110 abi_ulong sc_addr;
5111 int err = 0;
5112 int i;
5113
5114 frame_addr = get_sigframe(ka, env, sizeof *frame);
5115 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5116 goto give_sigsegv;
5117
5118 err |= __put_user(sig, &frame->sig);
5119
5120 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
5121 err |= __put_user(sc_addr, &frame->psc);
5122
5123 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
5124 if (err)
5125 goto give_sigsegv;
5126
5127 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5128 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
5129 goto give_sigsegv;
5130 }
5131
5132 /* Set up to return from userspace. */
5133
5134 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5135 err |= __put_user(retcode_addr, &frame->pretcode);
5136
5137 /* moveq #,d0; trap #0 */
5138
5139 err |= __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
5140 (long *)(frame->retcode));
5141
5142 if (err)
5143 goto give_sigsegv;
5144
5145 /* Set up to return from userspace */
5146
5147 env->aregs[7] = frame_addr;
5148 env->pc = ka->_sa_handler;
5149
5150 unlock_user_struct(frame, frame_addr, 1);
5151 return;
5152
5153give_sigsegv:
5154 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005155 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005156}
5157
Laurent Vivier71811552009-08-03 16:12:18 +02005158static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005159 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005160{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005161 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005162 int err;
5163
Aurelien Jarno60e99242010-03-29 02:12:51 +02005164 err = __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005165 err |= __put_user(env->dregs[0], &gregs[0]);
5166 err |= __put_user(env->dregs[1], &gregs[1]);
5167 err |= __put_user(env->dregs[2], &gregs[2]);
5168 err |= __put_user(env->dregs[3], &gregs[3]);
5169 err |= __put_user(env->dregs[4], &gregs[4]);
5170 err |= __put_user(env->dregs[5], &gregs[5]);
5171 err |= __put_user(env->dregs[6], &gregs[6]);
5172 err |= __put_user(env->dregs[7], &gregs[7]);
5173 err |= __put_user(env->aregs[0], &gregs[8]);
5174 err |= __put_user(env->aregs[1], &gregs[9]);
5175 err |= __put_user(env->aregs[2], &gregs[10]);
5176 err |= __put_user(env->aregs[3], &gregs[11]);
5177 err |= __put_user(env->aregs[4], &gregs[12]);
5178 err |= __put_user(env->aregs[5], &gregs[13]);
5179 err |= __put_user(env->aregs[6], &gregs[14]);
5180 err |= __put_user(env->aregs[7], &gregs[15]);
5181 err |= __put_user(env->pc, &gregs[16]);
5182 err |= __put_user(env->sr, &gregs[17]);
5183
5184 return err;
5185}
5186
Andreas Färber05390242012-02-25 03:37:53 +01005187static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005188 struct target_ucontext *uc,
5189 int *pd0)
5190{
5191 int temp;
5192 int err;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005193 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005194
Aurelien Jarno60e99242010-03-29 02:12:51 +02005195 err = __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005196 if (temp != TARGET_MCONTEXT_VERSION)
5197 goto badframe;
5198
5199 /* restore passed registers */
5200 err |= __get_user(env->dregs[0], &gregs[0]);
5201 err |= __get_user(env->dregs[1], &gregs[1]);
5202 err |= __get_user(env->dregs[2], &gregs[2]);
5203 err |= __get_user(env->dregs[3], &gregs[3]);
5204 err |= __get_user(env->dregs[4], &gregs[4]);
5205 err |= __get_user(env->dregs[5], &gregs[5]);
5206 err |= __get_user(env->dregs[6], &gregs[6]);
5207 err |= __get_user(env->dregs[7], &gregs[7]);
5208 err |= __get_user(env->aregs[0], &gregs[8]);
5209 err |= __get_user(env->aregs[1], &gregs[9]);
5210 err |= __get_user(env->aregs[2], &gregs[10]);
5211 err |= __get_user(env->aregs[3], &gregs[11]);
5212 err |= __get_user(env->aregs[4], &gregs[12]);
5213 err |= __get_user(env->aregs[5], &gregs[13]);
5214 err |= __get_user(env->aregs[6], &gregs[14]);
5215 err |= __get_user(env->aregs[7], &gregs[15]);
5216 err |= __get_user(env->pc, &gregs[16]);
5217 err |= __get_user(temp, &gregs[17]);
5218 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5219
5220 *pd0 = env->dregs[0];
5221 return err;
5222
5223badframe:
5224 return 1;
5225}
5226
Laurent Vivier492a8742009-08-03 16:12:17 +02005227static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005228 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005229 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005230{
Laurent Vivier71811552009-08-03 16:12:18 +02005231 struct target_rt_sigframe *frame;
5232 abi_ulong frame_addr;
5233 abi_ulong retcode_addr;
5234 abi_ulong info_addr;
5235 abi_ulong uc_addr;
5236 int err = 0;
5237 int i;
5238
5239 frame_addr = get_sigframe(ka, env, sizeof *frame);
5240 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5241 goto give_sigsegv;
5242
5243 err |= __put_user(sig, &frame->sig);
5244
5245 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
5246 err |= __put_user(info_addr, &frame->pinfo);
5247
5248 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
5249 err |= __put_user(uc_addr, &frame->puc);
5250
5251 err |= copy_siginfo_to_user(&frame->info, info);
5252
5253 /* Create the ucontext */
5254
Aurelien Jarno60e99242010-03-29 02:12:51 +02005255 err |= __put_user(0, &frame->uc.tuc_flags);
5256 err |= __put_user(0, &frame->uc.tuc_link);
Laurent Vivier71811552009-08-03 16:12:18 +02005257 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005258 &frame->uc.tuc_stack.ss_sp);
Laurent Vivier71811552009-08-03 16:12:18 +02005259 err |= __put_user(sas_ss_flags(env->aregs[7]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005260 &frame->uc.tuc_stack.ss_flags);
Laurent Vivier71811552009-08-03 16:12:18 +02005261 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005262 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005263 err |= target_rt_setup_ucontext(&frame->uc, env);
5264
5265 if (err)
5266 goto give_sigsegv;
5267
5268 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005269 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005270 goto give_sigsegv;
5271 }
5272
5273 /* Set up to return from userspace. */
5274
5275 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5276 err |= __put_user(retcode_addr, &frame->pretcode);
5277
5278 /* moveq #,d0; notb d0; trap #0 */
5279
5280 err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5281 (long *)(frame->retcode + 0));
5282 err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
5283
5284 if (err)
5285 goto give_sigsegv;
5286
5287 /* Set up to return from userspace */
5288
5289 env->aregs[7] = frame_addr;
5290 env->pc = ka->_sa_handler;
5291
5292 unlock_user_struct(frame, frame_addr, 1);
5293 return;
5294
5295give_sigsegv:
5296 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005297 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005298}
5299
Andreas Färber05390242012-02-25 03:37:53 +01005300long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005301{
5302 struct target_sigframe *frame;
5303 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005304 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005305 sigset_t set;
5306 int d0, i;
5307
5308 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5309 goto badframe;
5310
5311 /* set blocked signals */
5312
5313 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
5314 goto badframe;
5315
5316 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5317 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
5318 goto badframe;
5319 }
5320
5321 target_to_host_sigset_internal(&set, &target_set);
5322 sigprocmask(SIG_SETMASK, &set, NULL);
5323
5324 /* restore registers */
5325
5326 if (restore_sigcontext(env, &frame->sc, &d0))
5327 goto badframe;
5328
5329 unlock_user_struct(frame, frame_addr, 0);
5330 return d0;
5331
5332badframe:
5333 unlock_user_struct(frame, frame_addr, 0);
5334 force_sig(TARGET_SIGSEGV);
5335 return 0;
5336}
5337
Andreas Färber05390242012-02-25 03:37:53 +01005338long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005339{
Laurent Vivier71811552009-08-03 16:12:18 +02005340 struct target_rt_sigframe *frame;
5341 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005342 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005343 sigset_t set;
5344 int d0;
5345
5346 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5347 goto badframe;
5348
5349 target_to_host_sigset_internal(&set, &target_set);
5350 sigprocmask(SIG_SETMASK, &set, NULL);
5351
5352 /* restore registers */
5353
5354 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5355 goto badframe;
5356
5357 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005358 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005359 0, get_sp_from_cpustate(env)) == -EFAULT)
5360 goto badframe;
5361
5362 unlock_user_struct(frame, frame_addr, 0);
5363 return d0;
5364
5365badframe:
5366 unlock_user_struct(frame, frame_addr, 0);
5367 force_sig(TARGET_SIGSEGV);
5368 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005369}
5370
Richard Henderson6049f4f2009-12-27 18:30:03 -08005371#elif defined(TARGET_ALPHA)
5372
5373struct target_sigcontext {
5374 abi_long sc_onstack;
5375 abi_long sc_mask;
5376 abi_long sc_pc;
5377 abi_long sc_ps;
5378 abi_long sc_regs[32];
5379 abi_long sc_ownedfp;
5380 abi_long sc_fpregs[32];
5381 abi_ulong sc_fpcr;
5382 abi_ulong sc_fp_control;
5383 abi_ulong sc_reserved1;
5384 abi_ulong sc_reserved2;
5385 abi_ulong sc_ssize;
5386 abi_ulong sc_sbase;
5387 abi_ulong sc_traparg_a0;
5388 abi_ulong sc_traparg_a1;
5389 abi_ulong sc_traparg_a2;
5390 abi_ulong sc_fp_trap_pc;
5391 abi_ulong sc_fp_trigger_sum;
5392 abi_ulong sc_fp_trigger_inst;
5393};
5394
5395struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005396 abi_ulong tuc_flags;
5397 abi_ulong tuc_link;
5398 abi_ulong tuc_osf_sigmask;
5399 target_stack_t tuc_stack;
5400 struct target_sigcontext tuc_mcontext;
5401 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005402};
5403
5404struct target_sigframe {
5405 struct target_sigcontext sc;
5406 unsigned int retcode[3];
5407};
5408
5409struct target_rt_sigframe {
5410 target_siginfo_t info;
5411 struct target_ucontext uc;
5412 unsigned int retcode[3];
5413};
5414
5415#define INSN_MOV_R30_R16 0x47fe0410
5416#define INSN_LDI_R0 0x201f0000
5417#define INSN_CALLSYS 0x00000083
5418
Andreas Färber05390242012-02-25 03:37:53 +01005419static int setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005420 abi_ulong frame_addr, target_sigset_t *set)
5421{
5422 int i, err = 0;
5423
5424 err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5425 err |= __put_user(set->sig[0], &sc->sc_mask);
5426 err |= __put_user(env->pc, &sc->sc_pc);
5427 err |= __put_user(8, &sc->sc_ps);
5428
5429 for (i = 0; i < 31; ++i) {
5430 err |= __put_user(env->ir[i], &sc->sc_regs[i]);
5431 }
5432 err |= __put_user(0, &sc->sc_regs[31]);
5433
5434 for (i = 0; i < 31; ++i) {
5435 err |= __put_user(env->fir[i], &sc->sc_fpregs[i]);
5436 }
5437 err |= __put_user(0, &sc->sc_fpregs[31]);
5438 err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
5439
5440 err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5441 err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5442 err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */
5443
5444 return err;
5445}
5446
Andreas Färber05390242012-02-25 03:37:53 +01005447static int restore_sigcontext(CPUAlphaState *env,
5448 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005449{
5450 uint64_t fpcr;
5451 int i, err = 0;
5452
5453 err |= __get_user(env->pc, &sc->sc_pc);
5454
5455 for (i = 0; i < 31; ++i) {
5456 err |= __get_user(env->ir[i], &sc->sc_regs[i]);
5457 }
5458 for (i = 0; i < 31; ++i) {
5459 err |= __get_user(env->fir[i], &sc->sc_fpregs[i]);
5460 }
5461
5462 err |= __get_user(fpcr, &sc->sc_fpcr);
5463 cpu_alpha_store_fpcr(env, fpcr);
5464
5465 return err;
5466}
5467
5468static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005469 CPUAlphaState *env,
5470 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005471{
5472 abi_ulong sp = env->ir[IR_SP];
5473
5474 /* This is the X/Open sanctioned signal stack switching. */
5475 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5476 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5477 }
5478 return (sp - framesize) & -32;
5479}
5480
5481static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005482 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005483{
5484 abi_ulong frame_addr, r26;
5485 struct target_sigframe *frame;
5486 int err = 0;
5487
5488 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5489 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5490 goto give_sigsegv;
5491 }
5492
5493 err |= setup_sigcontext(&frame->sc, env, frame_addr, set);
5494
5495 if (ka->sa_restorer) {
5496 r26 = ka->sa_restorer;
5497 } else {
5498 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5499 err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5500 &frame->retcode[1]);
5501 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5502 /* imb() */
5503 r26 = frame_addr;
5504 }
5505
5506 unlock_user_struct(frame, frame_addr, 1);
5507
5508 if (err) {
5509 give_sigsegv:
5510 if (sig == TARGET_SIGSEGV) {
5511 ka->_sa_handler = TARGET_SIG_DFL;
5512 }
5513 force_sig(TARGET_SIGSEGV);
5514 }
5515
5516 env->ir[IR_RA] = r26;
5517 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5518 env->ir[IR_A0] = sig;
5519 env->ir[IR_A1] = 0;
5520 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5521 env->ir[IR_SP] = frame_addr;
5522}
5523
5524static void setup_rt_frame(int sig, struct target_sigaction *ka,
5525 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005526 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005527{
5528 abi_ulong frame_addr, r26;
5529 struct target_rt_sigframe *frame;
5530 int i, err = 0;
5531
5532 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5533 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5534 goto give_sigsegv;
5535 }
5536
5537 err |= copy_siginfo_to_user(&frame->info, info);
5538
Aurelien Jarno60e99242010-03-29 02:12:51 +02005539 err |= __put_user(0, &frame->uc.tuc_flags);
5540 err |= __put_user(0, &frame->uc.tuc_link);
5541 err |= __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005542 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005543 &frame->uc.tuc_stack.ss_sp);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005544 err |= __put_user(sas_ss_flags(env->ir[IR_SP]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005545 &frame->uc.tuc_stack.ss_flags);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005546 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005547 &frame->uc.tuc_stack.ss_size);
5548 err |= setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005549 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005550 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005551 }
5552
5553 if (ka->sa_restorer) {
5554 r26 = ka->sa_restorer;
5555 } else {
5556 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5557 err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5558 &frame->retcode[1]);
5559 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5560 /* imb(); */
5561 r26 = frame_addr;
5562 }
5563
5564 if (err) {
5565 give_sigsegv:
5566 if (sig == TARGET_SIGSEGV) {
5567 ka->_sa_handler = TARGET_SIG_DFL;
5568 }
5569 force_sig(TARGET_SIGSEGV);
5570 }
5571
5572 env->ir[IR_RA] = r26;
5573 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5574 env->ir[IR_A0] = sig;
5575 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5576 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5577 env->ir[IR_SP] = frame_addr;
5578}
5579
Andreas Färber05390242012-02-25 03:37:53 +01005580long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005581{
5582 struct target_sigcontext *sc;
5583 abi_ulong sc_addr = env->ir[IR_A0];
5584 target_sigset_t target_set;
5585 sigset_t set;
5586
5587 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5588 goto badframe;
5589 }
5590
5591 target_sigemptyset(&target_set);
5592 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
5593 goto badframe;
5594 }
5595
5596 target_to_host_sigset_internal(&set, &target_set);
5597 sigprocmask(SIG_SETMASK, &set, NULL);
5598
5599 if (restore_sigcontext(env, sc)) {
5600 goto badframe;
5601 }
5602 unlock_user_struct(sc, sc_addr, 0);
5603 return env->ir[IR_V0];
5604
5605 badframe:
5606 unlock_user_struct(sc, sc_addr, 0);
5607 force_sig(TARGET_SIGSEGV);
5608}
5609
Andreas Färber05390242012-02-25 03:37:53 +01005610long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005611{
5612 abi_ulong frame_addr = env->ir[IR_A0];
5613 struct target_rt_sigframe *frame;
5614 sigset_t set;
5615
5616 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5617 goto badframe;
5618 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005619 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005620 sigprocmask(SIG_SETMASK, &set, NULL);
5621
Aurelien Jarno60e99242010-03-29 02:12:51 +02005622 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005623 goto badframe;
5624 }
5625 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005626 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005627 0, env->ir[IR_SP]) == -EFAULT) {
5628 goto badframe;
5629 }
5630
5631 unlock_user_struct(frame, frame_addr, 0);
5632 return env->ir[IR_V0];
5633
5634
5635 badframe:
5636 unlock_user_struct(frame, frame_addr, 0);
5637 force_sig(TARGET_SIGSEGV);
5638}
5639
bellardb346ff42003-06-15 20:05:50 +00005640#else
5641
pbrook624f7972008-05-31 16:11:38 +00005642static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005643 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005644{
5645 fprintf(stderr, "setup_frame: not implemented\n");
5646}
5647
pbrook624f7972008-05-31 16:11:38 +00005648static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005649 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005650 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005651{
5652 fprintf(stderr, "setup_rt_frame: not implemented\n");
5653}
5654
Andreas Färber9349b4f2012-03-14 01:38:32 +01005655long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005656{
5657 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005658 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005659}
5660
Andreas Färber9349b4f2012-03-14 01:38:32 +01005661long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005662{
5663 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005664 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005665}
5666
bellard66fb9762003-03-23 01:06:05 +00005667#endif
5668
Andreas Färber9349b4f2012-03-14 01:38:32 +01005669void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005670{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005671 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005672 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005673 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005674 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005675 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005676 struct emulated_sigtable *k;
5677 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005678 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00005679 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00005680
pbrook624f7972008-05-31 16:11:38 +00005681 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005682 return;
5683
pbrook624f7972008-05-31 16:11:38 +00005684 /* FIXME: This is not threadsafe. */
5685 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005686 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5687 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005688 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005689 k++;
bellard31e31b82003-02-18 22:55:36 +00005690 }
5691 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005692 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005693 return;
bellard66fb9762003-03-23 01:06:05 +00005694
bellard31e31b82003-02-18 22:55:36 +00005695 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005696#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005697 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005698#endif
5699 /* dequeue signal */
5700 q = k->first;
5701 k->first = q->next;
5702 if (!k->first)
5703 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005704
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005705 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005706 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005707 sa = NULL;
5708 handler = TARGET_SIG_IGN;
5709 } else {
5710 sa = &sigact_table[sig - 1];
5711 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005712 }
bellard66fb9762003-03-23 01:06:05 +00005713
bellard66fb9762003-03-23 01:06:05 +00005714 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005715 /* default handler : ignore some signal. The other are job control or fatal */
5716 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5717 kill(getpid(),SIGSTOP);
5718 } else if (sig != TARGET_SIGCHLD &&
5719 sig != TARGET_SIGURG &&
5720 sig != TARGET_SIGWINCH &&
5721 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005722 force_sig(sig);
5723 }
5724 } else if (handler == TARGET_SIG_IGN) {
5725 /* ignore sig */
5726 } else if (handler == TARGET_SIG_ERR) {
5727 force_sig(sig);
5728 } else {
bellard9de5e442003-03-23 16:49:39 +00005729 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005730 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005731 /* SA_NODEFER indicates that the current signal should not be
5732 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005733 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005734 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005735
bellard9de5e442003-03-23 16:49:39 +00005736 /* block signals in the handler using Linux */
5737 sigprocmask(SIG_BLOCK, &set, &old_set);
5738 /* save the previous blocked signal state to restore it at the
5739 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005740 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005741
bellardbc8a22c2003-03-30 21:02:40 +00005742 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005743#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005744 {
5745 CPUX86State *env = cpu_env;
5746 if (env->eflags & VM_MASK)
5747 save_v86_state(env);
5748 }
5749#endif
bellard9de5e442003-03-23 16:49:39 +00005750 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005751#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5752 /* These targets do not have traditional signals. */
5753 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5754#else
pbrook624f7972008-05-31 16:11:38 +00005755 if (sa->sa_flags & TARGET_SA_SIGINFO)
5756 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005757 else
pbrook624f7972008-05-31 16:11:38 +00005758 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005759#endif
pbrook624f7972008-05-31 16:11:38 +00005760 if (sa->sa_flags & TARGET_SA_RESETHAND)
5761 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005762 }
bellard66fb9762003-03-23 01:06:05 +00005763 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005764 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005765}