blob: 96e86c0a29e986789fc797004c701663bdb0f029 [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 */
Peter Maydelld39594e2016-01-26 18:17:02 +000019#include "qemu/osdep.h"
bellard31e31b82003-02-18 22:55:36 +000020#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030021#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000022
bellard3ef693a2003-03-23 20:17:16 +000023#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000024#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000025#include "target_signal.h"
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +010026#include "trace.h"
bellard66fb9762003-03-23 01:06:05 +000027
blueswir1249c4c32008-10-05 11:09:37 +000028static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000029 .ss_sp = 0,
30 .ss_size = 0,
31 .ss_flags = TARGET_SS_DISABLE,
32};
33
pbrook624f7972008-05-31 16:11:38 +000034static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000035
ths5fafdf22007-09-16 21:08:06 +000036static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000037 void *puc);
38
Arnaud Patard3ca05582009-03-30 01:18:20 +020039static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000040 [SIGHUP] = TARGET_SIGHUP,
41 [SIGINT] = TARGET_SIGINT,
42 [SIGQUIT] = TARGET_SIGQUIT,
43 [SIGILL] = TARGET_SIGILL,
44 [SIGTRAP] = TARGET_SIGTRAP,
45 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000046/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGBUS] = TARGET_SIGBUS,
48 [SIGFPE] = TARGET_SIGFPE,
49 [SIGKILL] = TARGET_SIGKILL,
50 [SIGUSR1] = TARGET_SIGUSR1,
51 [SIGSEGV] = TARGET_SIGSEGV,
52 [SIGUSR2] = TARGET_SIGUSR2,
53 [SIGPIPE] = TARGET_SIGPIPE,
54 [SIGALRM] = TARGET_SIGALRM,
55 [SIGTERM] = TARGET_SIGTERM,
56#ifdef SIGSTKFLT
57 [SIGSTKFLT] = TARGET_SIGSTKFLT,
58#endif
59 [SIGCHLD] = TARGET_SIGCHLD,
60 [SIGCONT] = TARGET_SIGCONT,
61 [SIGSTOP] = TARGET_SIGSTOP,
62 [SIGTSTP] = TARGET_SIGTSTP,
63 [SIGTTIN] = TARGET_SIGTTIN,
64 [SIGTTOU] = TARGET_SIGTTOU,
65 [SIGURG] = TARGET_SIGURG,
66 [SIGXCPU] = TARGET_SIGXCPU,
67 [SIGXFSZ] = TARGET_SIGXFSZ,
68 [SIGVTALRM] = TARGET_SIGVTALRM,
69 [SIGPROF] = TARGET_SIGPROF,
70 [SIGWINCH] = TARGET_SIGWINCH,
71 [SIGIO] = TARGET_SIGIO,
72 [SIGPWR] = TARGET_SIGPWR,
73 [SIGSYS] = TARGET_SIGSYS,
74 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000075 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080076 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000077 To fix this properly we need to do manual signal delivery multiplexed
78 over a single host signal. */
79 [__SIGRTMIN] = __SIGRTMAX,
80 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000081};
Arnaud Patard3ca05582009-03-30 01:18:20 +020082static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000083
thsa04e1342007-09-27 13:57:58 +000084static inline int on_sig_stack(unsigned long sp)
85{
86 return (sp - target_sigaltstack_used.ss_sp
87 < target_sigaltstack_used.ss_size);
88}
89
90static inline int sas_ss_flags(unsigned long sp)
91{
92 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
93 : on_sig_stack(sp) ? SS_ONSTACK : 0);
94}
95
pbrook1d9d8b52009-04-16 15:17:02 +000096int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +000097{
Andreas Schwab167c50d2013-07-02 14:04:12 +010098 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +000099 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000100 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000101}
102
pbrook4cb05962008-05-30 18:05:19 +0000103int target_to_host_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 target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
Anthony Liguoric227f092009-10-01 16:12:16 -0500110static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000111{
112 memset(set, 0, sizeof(*set));
113}
114
Anthony Liguoric227f092009-10-01 16:12:16 -0500115static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000116{
117 signum--;
118 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
119 set->sig[signum / TARGET_NSIG_BPW] |= mask;
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline int target_sigismember(const 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 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000130 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000131{
132 int i;
pbrookf5545b52008-05-30 22:37:07 +0000133 target_sigemptyset(d);
134 for (i = 1; i <= TARGET_NSIG; i++) {
135 if (sigismember(s, i)) {
136 target_sigaddset(d, host_to_target_signal(i));
137 }
bellard9e5f5282003-07-13 17:33:54 +0000138 }
bellard66fb9762003-03-23 01:06:05 +0000139}
140
Anthony Liguoric227f092009-10-01 16:12:16 -0500141void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000142{
Anthony Liguoric227f092009-10-01 16:12:16 -0500143 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000144 int i;
145
146 host_to_target_sigset_internal(&d1, s);
147 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200148 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000149}
150
blueswir18fcd3692008-08-17 20:26:25 +0000151static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500152 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000153{
154 int i;
pbrookf5545b52008-05-30 22:37:07 +0000155 sigemptyset(d);
156 for (i = 1; i <= TARGET_NSIG; i++) {
157 if (target_sigismember(s, i)) {
158 sigaddset(d, target_to_host_signal(i));
159 }
160 }
bellard66fb9762003-03-23 01:06:05 +0000161}
162
Anthony Liguoric227f092009-10-01 16:12:16 -0500163void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000164{
Anthony Liguoric227f092009-10-01 16:12:16 -0500165 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000166 int i;
167
168 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200169 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000170 target_to_host_sigset_internal(d, &s1);
171}
ths3b46e622007-09-17 08:09:54 +0000172
blueswir1992f48a2007-10-14 16:27:31 +0000173void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000174 const sigset_t *sigset)
175{
Anthony Liguoric227f092009-10-01 16:12:16 -0500176 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000177 host_to_target_sigset(&d, sigset);
178 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000179}
180
ths5fafdf22007-09-16 21:08:06 +0000181void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000182 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000183{
Anthony Liguoric227f092009-10-01 16:12:16 -0500184 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000185 int i;
186
187 d.sig[0] = *old_sigset;
188 for(i = 1;i < TARGET_NSIG_WORDS; i++)
189 d.sig[i] = 0;
190 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000191}
192
Alex Barcelo1c275922014-03-14 14:36:55 +0000193/* Wrapper for sigprocmask function
194 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
195 * are host signal set, not guest ones. This wraps the sigprocmask host calls
196 * that should be protected (calls originated from guest)
197 */
198int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
199{
Peter Maydella7ec0f92014-03-14 14:36:56 +0000200 int ret;
201 sigset_t val;
202 sigset_t *temp = NULL;
203 CPUState *cpu = thread_cpu;
204 TaskState *ts = (TaskState *)cpu->opaque;
205 bool segv_was_blocked = ts->sigsegv_blocked;
206
207 if (set) {
208 bool has_sigsegv = sigismember(set, SIGSEGV);
209 val = *set;
210 temp = &val;
211
212 sigdelset(temp, SIGSEGV);
213
214 switch (how) {
215 case SIG_BLOCK:
216 if (has_sigsegv) {
217 ts->sigsegv_blocked = true;
218 }
219 break;
220 case SIG_UNBLOCK:
221 if (has_sigsegv) {
222 ts->sigsegv_blocked = false;
223 }
224 break;
225 case SIG_SETMASK:
226 ts->sigsegv_blocked = has_sigsegv;
227 break;
228 default:
229 g_assert_not_reached();
230 }
231 }
232
233 ret = sigprocmask(how, temp, oldset);
234
235 if (oldset && segv_was_blocked) {
236 sigaddset(oldset, SIGSEGV);
237 }
238
239 return ret;
Alex Barcelo1c275922014-03-14 14:36:55 +0000240}
241
bellard9de5e442003-03-23 16:49:39 +0000242/* siginfo conversion */
243
Anthony Liguoric227f092009-10-01 16:12:16 -0500244static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000245 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000246{
Richard Hendersona05c6402012-09-15 11:34:20 -0700247 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000248 tinfo->si_signo = sig;
249 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000250 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700251
252 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
253 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
254 /* Should never come here, but who knows. The information for
255 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000256 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700257 } else if (sig == TARGET_SIGIO) {
258 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000259 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700260 } else if (sig == TARGET_SIGCHLD) {
261 tinfo->_sifields._sigchld._pid = info->si_pid;
262 tinfo->_sifields._sigchld._uid = info->si_uid;
263 tinfo->_sifields._sigchld._status
264 = host_to_target_waitstatus(info->si_status);
265 tinfo->_sifields._sigchld._utime = info->si_utime;
266 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000267 } else if (sig >= TARGET_SIGRTMIN) {
268 tinfo->_sifields._rt._pid = info->si_pid;
269 tinfo->_sifields._rt._uid = info->si_uid;
270 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700271 tinfo->_sifields._rt._sigval.sival_ptr
272 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000273 }
bellard66fb9762003-03-23 01:06:05 +0000274}
275
Anthony Liguoric227f092009-10-01 16:12:16 -0500276static void tswap_siginfo(target_siginfo_t *tinfo,
277 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000278{
Richard Hendersona05c6402012-09-15 11:34:20 -0700279 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000280 tinfo->si_signo = tswap32(sig);
281 tinfo->si_errno = tswap32(info->si_errno);
282 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700283
284 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
285 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
286 tinfo->_sifields._sigfault._addr
287 = tswapal(info->_sifields._sigfault._addr);
288 } else if (sig == TARGET_SIGIO) {
289 tinfo->_sifields._sigpoll._band
290 = tswap32(info->_sifields._sigpoll._band);
291 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
292 } else if (sig == TARGET_SIGCHLD) {
293 tinfo->_sifields._sigchld._pid
294 = tswap32(info->_sifields._sigchld._pid);
295 tinfo->_sifields._sigchld._uid
296 = tswap32(info->_sifields._sigchld._uid);
297 tinfo->_sifields._sigchld._status
298 = tswap32(info->_sifields._sigchld._status);
299 tinfo->_sifields._sigchld._utime
300 = tswapal(info->_sifields._sigchld._utime);
301 tinfo->_sifields._sigchld._stime
302 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000303 } else if (sig >= TARGET_SIGRTMIN) {
304 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
305 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700306 tinfo->_sifields._rt._sigval.sival_ptr
307 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000308 }
309}
310
311
Anthony Liguoric227f092009-10-01 16:12:16 -0500312void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000313{
314 host_to_target_siginfo_noswap(tinfo, info);
315 tswap_siginfo(tinfo, tinfo);
316}
317
318/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000319/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500320void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000321{
322 info->si_signo = tswap32(tinfo->si_signo);
323 info->si_errno = tswap32(tinfo->si_errno);
324 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000325 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
326 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000327 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200328 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000329}
330
aurel32ca587a82008-12-18 22:44:13 +0000331static int fatal_signal (int sig)
332{
333 switch (sig) {
334 case TARGET_SIGCHLD:
335 case TARGET_SIGURG:
336 case TARGET_SIGWINCH:
337 /* Ignored by default. */
338 return 0;
339 case TARGET_SIGCONT:
340 case TARGET_SIGSTOP:
341 case TARGET_SIGTSTP:
342 case TARGET_SIGTTIN:
343 case TARGET_SIGTTOU:
344 /* Job control signals. */
345 return 0;
346 default:
347 return 1;
348 }
349}
350
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300351/* returns 1 if given signal should dump core if not handled */
352static int core_dump_signal(int sig)
353{
354 switch (sig) {
355 case TARGET_SIGABRT:
356 case TARGET_SIGFPE:
357 case TARGET_SIGILL:
358 case TARGET_SIGQUIT:
359 case TARGET_SIGSEGV:
360 case TARGET_SIGTRAP:
361 case TARGET_SIGBUS:
362 return (1);
363 default:
364 return (0);
365 }
366}
367
bellard31e31b82003-02-18 22:55:36 +0000368void signal_init(void)
369{
370 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000371 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000372 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000373 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000374
bellard9e5f5282003-07-13 17:33:54 +0000375 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200376 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000377 if (host_to_target_signal_table[i] == 0)
378 host_to_target_signal_table[i] = i;
379 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200380 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000381 j = host_to_target_signal_table[i];
382 target_to_host_signal_table[j] = i;
383 }
ths3b46e622007-09-17 08:09:54 +0000384
bellard9de5e442003-03-23 16:49:39 +0000385 /* set all host signal handlers. ALL signals are blocked during
386 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000387 memset(sigact_table, 0, sizeof(sigact_table));
388
bellard9de5e442003-03-23 16:49:39 +0000389 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000390 act.sa_flags = SA_SIGINFO;
391 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000392 for(i = 1; i <= TARGET_NSIG; i++) {
393 host_sig = target_to_host_signal(i);
394 sigaction(host_sig, NULL, &oact);
395 if (oact.sa_sigaction == (void *)SIG_IGN) {
396 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
397 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
398 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
399 }
400 /* If there's already a handler installed then something has
401 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000402 /* Install some handlers for our own use. We need at least
403 SIGSEGV and SIGBUS, to detect exceptions. We can not just
404 trap all signals because it affects syscall interrupt
405 behavior. But do trap all default-fatal signals. */
406 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000407 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000408 }
bellard31e31b82003-02-18 22:55:36 +0000409}
410
bellard66fb9762003-03-23 01:06:05 +0000411/* signal queue handling */
412
Andreas Färber9349b4f2012-03-14 01:38:32 +0100413static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000414{
Andreas Färber0429a972013-08-26 18:14:44 +0200415 CPUState *cpu = ENV_GET_CPU(env);
416 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000417 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000418 if (!q)
419 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000420 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000421 return q;
422}
423
Andreas Färber9349b4f2012-03-14 01:38:32 +0100424static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000425{
Andreas Färber0429a972013-08-26 18:14:44 +0200426 CPUState *cpu = ENV_GET_CPU(env);
427 TaskState *ts = cpu->opaque;
428
pbrook624f7972008-05-31 16:11:38 +0000429 q->next = ts->first_free;
430 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000431}
432
bellard9de5e442003-03-23 16:49:39 +0000433/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200434static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000435{
Andreas Färber0429a972013-08-26 18:14:44 +0200436 CPUState *cpu = thread_cpu;
437 CPUArchState *env = cpu->env_ptr;
438 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300439 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000440 struct sigaction act;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100441
Riku Voipio66393fb2009-12-04 15:16:32 +0200442 host_sig = target_to_host_signal(target_sig);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100443 trace_user_force_sig(env, target_sig, host_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200444 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000445
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300446 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200447 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300448 stop_all_tasks();
449 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200450 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300451 }
452 if (core_dumped) {
453 /* we already dumped the core of target process, we don't want
454 * a coredump of qemu itself */
455 struct rlimit nodump;
456 getrlimit(RLIMIT_CORE, &nodump);
457 nodump.rlim_cur=0;
458 setrlimit(RLIMIT_CORE, &nodump);
459 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200460 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300461 }
462
Stefan Weil0c587512011-04-28 17:20:32 +0200463 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000464 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
465 * a negative value. To get the proper exit code we need to
466 * actually die from an uncaught signal. Here the default signal
467 * handler is installed, we send ourself a signal and we wait for
468 * it to arrive. */
469 sigfillset(&act.sa_mask);
470 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000471 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000472 sigaction(host_sig, &act, NULL);
473
474 /* For some reason raise(host_sig) doesn't send the signal when
475 * statically linked on x86-64. */
476 kill(getpid(), host_sig);
477
478 /* Make sure the signal isn't masked (just reuse the mask inside
479 of act) */
480 sigdelset(&act.sa_mask, host_sig);
481 sigsuspend(&act.sa_mask);
482
483 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000484 abort();
bellard66fb9762003-03-23 01:06:05 +0000485}
486
bellard9de5e442003-03-23 16:49:39 +0000487/* queue a signal so that it will be send to the virtual CPU as soon
488 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100489int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000490{
Andreas Färber0429a972013-08-26 18:14:44 +0200491 CPUState *cpu = ENV_GET_CPU(env);
492 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000493 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000494 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000495 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000496 int queue;
bellard66fb9762003-03-23 01:06:05 +0000497
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100498 trace_user_queue_signal(env, sig);
pbrook624f7972008-05-31 16:11:38 +0000499 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000500 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000501 handler = sigact_table[sig - 1]._sa_handler;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000502
503 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
504 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
505 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
506 * because it got a real MMU fault). A blocked SIGSEGV in that
507 * situation is treated as if using the default handler. This is
508 * not correct if some other process has randomly sent us a SIGSEGV
509 * via kill(), but that is not easy to distinguish at this point,
510 * so we assume it doesn't happen.
511 */
512 handler = TARGET_SIG_DFL;
513 }
514
aurel32ca587a82008-12-18 22:44:13 +0000515 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000516 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
517 kill(getpid(),SIGSTOP);
518 return 0;
519 } else
bellard66fb9762003-03-23 01:06:05 +0000520 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000521 if (sig != TARGET_SIGCHLD &&
522 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000523 sig != TARGET_SIGWINCH &&
524 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000525 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000526 } else {
527 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000528 }
aurel32ca587a82008-12-18 22:44:13 +0000529 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000530 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000531 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000532 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000533 force_sig(sig);
534 } else {
bellard9de5e442003-03-23 16:49:39 +0000535 pq = &k->first;
536 if (sig < TARGET_SIGRTMIN) {
537 /* if non real time signal, we queue exactly one signal */
538 if (!k->pending)
539 q = &k->info;
540 else
541 return 0;
542 } else {
543 if (!k->pending) {
544 /* first signal */
545 q = &k->info;
546 } else {
pbrook624f7972008-05-31 16:11:38 +0000547 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000548 if (!q)
549 return -EAGAIN;
550 while (*pq != NULL)
551 pq = &(*pq)->next;
552 }
553 }
554 *pq = q;
555 q->info = *info;
556 q->next = NULL;
557 k->pending = 1;
558 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000559 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000560 return 1; /* indicates that the signal was queued */
561 }
562}
563
ths5fafdf22007-09-16 21:08:06 +0000564static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000565 void *puc)
566{
Andreas Färbera2247f82013-06-09 19:47:04 +0200567 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000568 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500569 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000570
571 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000572 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000573 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000574 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000575 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000576 return;
577 }
578
579 /* get target signal number */
580 sig = host_to_target_signal(host_signum);
581 if (sig < 1 || sig > TARGET_NSIG)
582 return;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100583 trace_user_host_signal(env, host_signum, sig);
bellard9de5e442003-03-23 16:49:39 +0000584 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200585 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000586 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200587 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000588 }
bellard31e31b82003-02-18 22:55:36 +0000589}
590
ths0da46a62007-10-20 20:23:07 +0000591/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000592/* compare linux/kernel/signal.c:do_sigaltstack() */
593abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000594{
595 int ret;
596 struct target_sigaltstack oss;
597
598 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000599 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000600 {
601 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
602 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
603 __put_user(sas_ss_flags(sp), &oss.ss_flags);
604 }
605
bellard579a97f2007-11-11 14:26:47 +0000606 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000607 {
bellard579a97f2007-11-11 14:26:47 +0000608 struct target_sigaltstack *uss;
609 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500610 size_t minstacksize = TARGET_MINSIGSTKSZ;
611
612#if defined(TARGET_PPC64)
613 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
614 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
615 if (get_ppc64_abi(image) > 1) {
616 minstacksize = 4096;
617 }
618#endif
thsa04e1342007-09-27 13:57:58 +0000619
ths0da46a62007-10-20 20:23:07 +0000620 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300621 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000622 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300623 }
624 __get_user(ss.ss_sp, &uss->ss_sp);
625 __get_user(ss.ss_size, &uss->ss_size);
626 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000627 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000628
ths0da46a62007-10-20 20:23:07 +0000629 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000630 if (on_sig_stack(sp))
631 goto out;
632
ths0da46a62007-10-20 20:23:07 +0000633 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000634 if (ss.ss_flags != TARGET_SS_DISABLE
635 && ss.ss_flags != TARGET_SS_ONSTACK
636 && ss.ss_flags != 0)
637 goto out;
638
639 if (ss.ss_flags == TARGET_SS_DISABLE) {
640 ss.ss_size = 0;
641 ss.ss_sp = 0;
642 } else {
ths0da46a62007-10-20 20:23:07 +0000643 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500644 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000645 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500646 }
thsa04e1342007-09-27 13:57:58 +0000647 }
648
649 target_sigaltstack_used.ss_sp = ss.ss_sp;
650 target_sigaltstack_used.ss_size = ss.ss_size;
651 }
652
bellard579a97f2007-11-11 14:26:47 +0000653 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000654 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000655 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000656 goto out;
thsa04e1342007-09-27 13:57:58 +0000657 }
658
659 ret = 0;
660out:
661 return ret;
662}
663
ths0da46a62007-10-20 20:23:07 +0000664/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000665int do_sigaction(int sig, const struct target_sigaction *act,
666 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000667{
pbrook624f7972008-05-31 16:11:38 +0000668 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000669 struct sigaction act1;
670 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000671 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000672
ths2a913eb2008-11-27 15:46:25 +0000673 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000674 return -EINVAL;
675 k = &sigact_table[sig - 1];
bellard66fb9762003-03-23 01:06:05 +0000676 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800677 __put_user(k->_sa_handler, &oact->_sa_handler);
678 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000679#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800680 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000681#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800682 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000683 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000684 }
685 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000686 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800687 __get_user(k->_sa_handler, &act->_sa_handler);
688 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000689#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800690 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000691#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800692 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000693 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000694
695 /* we update the host linux signal state */
696 host_sig = target_to_host_signal(sig);
697 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
698 sigfillset(&act1.sa_mask);
699 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000700 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000701 act1.sa_flags |= SA_RESTART;
702 /* NOTE: it is important to update the host kernel signal
703 ignore state to avoid getting unexpected interrupted
704 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000705 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000706 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000707 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000708 if (fatal_signal (sig))
709 act1.sa_sigaction = host_signal_handler;
710 else
711 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000712 } else {
713 act1.sa_sigaction = host_signal_handler;
714 }
ths0da46a62007-10-20 20:23:07 +0000715 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000716 }
bellard66fb9762003-03-23 01:06:05 +0000717 }
ths0da46a62007-10-20 20:23:07 +0000718 return ret;
bellard66fb9762003-03-23 01:06:05 +0000719}
bellard31e31b82003-02-18 22:55:36 +0000720
bellard459a4012007-11-11 19:45:10 +0000721#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000722
723/* from the Linux kernel */
724
725struct target_fpreg {
726 uint16_t significand[4];
727 uint16_t exponent;
728};
729
730struct target_fpxreg {
731 uint16_t significand[4];
732 uint16_t exponent;
733 uint16_t padding[3];
734};
735
736struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000737 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000738};
739
740struct target_fpstate {
741 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000742 abi_ulong cw;
743 abi_ulong sw;
744 abi_ulong tag;
745 abi_ulong ipoff;
746 abi_ulong cssel;
747 abi_ulong dataoff;
748 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000749 struct target_fpreg _st[8];
750 uint16_t status;
751 uint16_t magic; /* 0xffff = regular FPU data only */
752
753 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000754 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
755 abi_ulong mxcsr;
756 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000757 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
758 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000759 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000760};
761
762#define X86_FXSR_MAGIC 0x0000
763
764struct target_sigcontext {
765 uint16_t gs, __gsh;
766 uint16_t fs, __fsh;
767 uint16_t es, __esh;
768 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000769 abi_ulong edi;
770 abi_ulong esi;
771 abi_ulong ebp;
772 abi_ulong esp;
773 abi_ulong ebx;
774 abi_ulong edx;
775 abi_ulong ecx;
776 abi_ulong eax;
777 abi_ulong trapno;
778 abi_ulong err;
779 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000780 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000781 abi_ulong eflags;
782 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000783 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000784 abi_ulong fpstate; /* pointer */
785 abi_ulong oldmask;
786 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000787};
788
bellard66fb9762003-03-23 01:06:05 +0000789struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000790 abi_ulong tuc_flags;
791 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500792 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000793 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500794 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000795};
796
797struct sigframe
798{
blueswir1992f48a2007-10-14 16:27:31 +0000799 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000800 int sig;
801 struct target_sigcontext sc;
802 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000803 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000804 char retcode[8];
805};
806
807struct rt_sigframe
808{
blueswir1992f48a2007-10-14 16:27:31 +0000809 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000810 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000811 abi_ulong pinfo;
812 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000813 struct target_siginfo info;
814 struct target_ucontext uc;
815 struct target_fpstate fpstate;
816 char retcode[8];
817};
818
819/*
820 * Set up a signal frame.
821 */
822
bellard66fb9762003-03-23 01:06:05 +0000823/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300824static void setup_sigcontext(struct target_sigcontext *sc,
825 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
826 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000827{
Andreas Färber27103422013-08-26 08:31:06 +0200828 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200829 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000830
bellard579a97f2007-11-11 14:26:47 +0000831 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300832 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
833 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
834 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
835 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
836 __put_user(env->regs[R_EDI], &sc->edi);
837 __put_user(env->regs[R_ESI], &sc->esi);
838 __put_user(env->regs[R_EBP], &sc->ebp);
839 __put_user(env->regs[R_ESP], &sc->esp);
840 __put_user(env->regs[R_EBX], &sc->ebx);
841 __put_user(env->regs[R_EDX], &sc->edx);
842 __put_user(env->regs[R_ECX], &sc->ecx);
843 __put_user(env->regs[R_EAX], &sc->eax);
844 __put_user(cs->exception_index, &sc->trapno);
845 __put_user(env->error_code, &sc->err);
846 __put_user(env->eip, &sc->eip);
847 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
848 __put_user(env->eflags, &sc->eflags);
849 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
850 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000851
bellard28be6232007-11-11 22:23:38 +0000852 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000853 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000854 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300855 __put_user(magic, &fpstate->magic);
856 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000857
bellard66fb9762003-03-23 01:06:05 +0000858 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300859 __put_user(mask, &sc->oldmask);
860 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000861}
862
863/*
864 * Determine which stack to use..
865 */
866
bellard579a97f2007-11-11 14:26:47 +0000867static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000868get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000869{
870 unsigned long esp;
871
872 /* Default to using normal stack */
873 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000874 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000875 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000876 if (sas_ss_flags(esp) == 0)
877 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
878 }
bellard66fb9762003-03-23 01:06:05 +0000879
880 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000881 else
bellarda52c7572003-06-21 13:14:12 +0000882 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000883 !(ka->sa_flags & TARGET_SA_RESTORER) &&
884 ka->sa_restorer) {
885 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000886 }
bellard579a97f2007-11-11 14:26:47 +0000887 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000888}
889
bellard579a97f2007-11-11 14:26:47 +0000890/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000891static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500892 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000893{
bellard579a97f2007-11-11 14:26:47 +0000894 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000895 struct sigframe *frame;
Riku Voipio7df2fa32014-04-23 10:34:53 +0300896 int i;
bellard66fb9762003-03-23 01:06:05 +0000897
bellard579a97f2007-11-11 14:26:47 +0000898 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100899 trace_user_setup_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000900
bellard579a97f2007-11-11 14:26:47 +0000901 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000902 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000903
Peter Maydellb6e2c932015-01-08 12:19:43 +0000904 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000905
bellard28be6232007-11-11 22:23:38 +0000906 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
907 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000908
Riku Voipio7df2fa32014-04-23 10:34:53 +0300909 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
910 __put_user(set->sig[i], &frame->extramask[i - 1]);
911 }
bellard66fb9762003-03-23 01:06:05 +0000912
913 /* Set up to return from userspace. If provided, use a stub
914 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000915 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300916 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000917 } else {
bellard775b58d2007-11-11 16:22:17 +0000918 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000919 abi_ulong retcode_addr;
920 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300921 __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000922 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000923 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300924 __put_user(val16, (uint16_t *)(frame->retcode+0));
925 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000926 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300927 __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000928 }
929
bellard66fb9762003-03-23 01:06:05 +0000930
931 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000932 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000933 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000934
935 cpu_x86_load_seg(env, R_DS, __USER_DS);
936 cpu_x86_load_seg(env, R_ES, __USER_DS);
937 cpu_x86_load_seg(env, R_SS, __USER_DS);
938 cpu_x86_load_seg(env, R_CS, __USER_CS);
939 env->eflags &= ~TF_MASK;
940
bellard579a97f2007-11-11 14:26:47 +0000941 unlock_user_struct(frame, frame_addr, 1);
942
bellard66fb9762003-03-23 01:06:05 +0000943 return;
944
945give_sigsegv:
946 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000947 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000948 force_sig(TARGET_SIGSEGV /* , current */);
949}
950
bellard579a97f2007-11-11 14:26:47 +0000951/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000952static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500953 target_siginfo_t *info,
954 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000955{
bellard28be6232007-11-11 22:23:38 +0000956 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000957 struct rt_sigframe *frame;
Riku Voipio0188fad2014-04-23 13:34:15 +0300958 int i;
bellard66fb9762003-03-23 01:06:05 +0000959
bellard579a97f2007-11-11 14:26:47 +0000960 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100961 trace_user_setup_rt_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000962
bellard579a97f2007-11-11 14:26:47 +0000963 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000964 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000965
Peter Maydellb6e2c932015-01-08 12:19:43 +0000966 __put_user(sig, &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000967 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300968 __put_user(addr, &frame->pinfo);
bellard28be6232007-11-11 22:23:38 +0000969 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300970 __put_user(addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +0000971 tswap_siginfo(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +0000972
973 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300974 __put_user(0, &frame->uc.tuc_flags);
975 __put_user(0, &frame->uc.tuc_link);
976 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
977 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
978 &frame->uc.tuc_stack.ss_flags);
979 __put_user(target_sigaltstack_used.ss_size,
980 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +0300981 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
982 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
983
Riku Voipio0188fad2014-04-23 13:34:15 +0300984 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
985 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
986 }
bellard66fb9762003-03-23 01:06:05 +0000987
988 /* Set up to return from userspace. If provided, use a stub
989 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000990 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300991 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000992 } else {
bellard775b58d2007-11-11 16:22:17 +0000993 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000994 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300995 __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000996 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300997 __put_user(0xb8, (char *)(frame->retcode+0));
998 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000999 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001000 __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +00001001 }
1002
bellard66fb9762003-03-23 01:06:05 +00001003 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +00001004 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +00001005 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001006
1007 cpu_x86_load_seg(env, R_DS, __USER_DS);
1008 cpu_x86_load_seg(env, R_ES, __USER_DS);
1009 cpu_x86_load_seg(env, R_SS, __USER_DS);
1010 cpu_x86_load_seg(env, R_CS, __USER_CS);
1011 env->eflags &= ~TF_MASK;
1012
bellard579a97f2007-11-11 14:26:47 +00001013 unlock_user_struct(frame, frame_addr, 1);
1014
bellard66fb9762003-03-23 01:06:05 +00001015 return;
1016
1017give_sigsegv:
1018 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001019 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001020 force_sig(TARGET_SIGSEGV /* , current */);
1021}
1022
1023static int
1024restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1025{
1026 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001027 abi_ulong fpstate_addr;
1028 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001029
bellard28be6232007-11-11 22:23:38 +00001030 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1031 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1032 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1033 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001034
bellard28be6232007-11-11 22:23:38 +00001035 env->regs[R_EDI] = tswapl(sc->edi);
1036 env->regs[R_ESI] = tswapl(sc->esi);
1037 env->regs[R_EBP] = tswapl(sc->ebp);
1038 env->regs[R_ESP] = tswapl(sc->esp);
1039 env->regs[R_EBX] = tswapl(sc->ebx);
1040 env->regs[R_EDX] = tswapl(sc->edx);
1041 env->regs[R_ECX] = tswapl(sc->ecx);
1042 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001043
Mike McCormack9a826d72011-06-01 15:14:37 +09001044 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1045 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001046
bellard28be6232007-11-11 22:23:38 +00001047 tmpflags = tswapl(sc->eflags);
1048 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1049 // regs->orig_eax = -1; /* disable syscall checks */
1050
1051 fpstate_addr = tswapl(sc->fpstate);
1052 if (fpstate_addr != 0) {
1053 if (!access_ok(VERIFY_READ, fpstate_addr,
1054 sizeof(struct target_fpstate)))
1055 goto badframe;
1056 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001057 }
1058
bellard28be6232007-11-11 22:23:38 +00001059 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001060 return err;
bellard66fb9762003-03-23 01:06:05 +00001061badframe:
1062 return 1;
bellard66fb9762003-03-23 01:06:05 +00001063}
1064
1065long do_sigreturn(CPUX86State *env)
1066{
bellard579a97f2007-11-11 14:26:47 +00001067 struct sigframe *frame;
1068 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001069 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001070 sigset_t set;
1071 int eax, i;
1072
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001073 trace_user_do_sigreturn(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001074 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1075 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001076 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001077 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001078 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001079 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001080 }
bellard66fb9762003-03-23 01:06:05 +00001081
bellard92319442004-06-19 16:58:13 +00001082 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001083 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001084
bellard66fb9762003-03-23 01:06:05 +00001085 /* restore registers */
1086 if (restore_sigcontext(env, &frame->sc, &eax))
1087 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001088 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001089 return eax;
1090
1091badframe:
bellard579a97f2007-11-11 14:26:47 +00001092 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001093 force_sig(TARGET_SIGSEGV);
1094 return 0;
1095}
1096
1097long do_rt_sigreturn(CPUX86State *env)
1098{
bellard28be6232007-11-11 22:23:38 +00001099 abi_ulong frame_addr;
1100 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001101 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001102 int eax;
1103
bellard28be6232007-11-11 22:23:38 +00001104 frame_addr = env->regs[R_ESP] - 4;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001105 trace_user_do_rt_sigreturn(env, frame_addr);
bellard28be6232007-11-11 22:23:38 +00001106 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1107 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001108 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001109 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001110
bellardb8076a72005-04-07 22:20:31 +00001111 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001112 goto badframe;
1113
bellard28be6232007-11-11 22:23:38 +00001114 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1115 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001116 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001117
bellard28be6232007-11-11 22:23:38 +00001118 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001119 return eax;
1120
1121badframe:
bellard28be6232007-11-11 22:23:38 +00001122 unlock_user_struct(frame, frame_addr, 0);
1123 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001124 return 0;
1125}
1126
Andreas Schwab1744aea2013-09-03 20:12:16 +01001127#elif defined(TARGET_AARCH64)
1128
1129struct target_sigcontext {
1130 uint64_t fault_address;
1131 /* AArch64 registers */
1132 uint64_t regs[31];
1133 uint64_t sp;
1134 uint64_t pc;
1135 uint64_t pstate;
1136 /* 4K reserved for FP/SIMD state and future expansion */
1137 char __reserved[4096] __attribute__((__aligned__(16)));
1138};
1139
1140struct target_ucontext {
1141 abi_ulong tuc_flags;
1142 abi_ulong tuc_link;
1143 target_stack_t tuc_stack;
1144 target_sigset_t tuc_sigmask;
1145 /* glibc uses a 1024-bit sigset_t */
1146 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1147 /* last for future expansion */
1148 struct target_sigcontext tuc_mcontext;
1149};
1150
1151/*
1152 * Header to be used at the beginning of structures extending the user
1153 * context. Such structures must be placed after the rt_sigframe on the stack
1154 * and be 16-byte aligned. The last structure must be a dummy one with the
1155 * magic and size set to 0.
1156 */
1157struct target_aarch64_ctx {
1158 uint32_t magic;
1159 uint32_t size;
1160};
1161
1162#define TARGET_FPSIMD_MAGIC 0x46508001
1163
1164struct target_fpsimd_context {
1165 struct target_aarch64_ctx head;
1166 uint32_t fpsr;
1167 uint32_t fpcr;
1168 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1169};
1170
1171/*
1172 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1173 * user space as it will change with the addition of new context. User space
1174 * should check the magic/size information.
1175 */
1176struct target_aux_context {
1177 struct target_fpsimd_context fpsimd;
1178 /* additional context to be added before "end" */
1179 struct target_aarch64_ctx end;
1180};
1181
1182struct target_rt_sigframe {
1183 struct target_siginfo info;
1184 struct target_ucontext uc;
1185 uint64_t fp;
1186 uint64_t lr;
1187 uint32_t tramp[2];
1188};
1189
1190static int target_setup_sigframe(struct target_rt_sigframe *sf,
1191 CPUARMState *env, target_sigset_t *set)
1192{
1193 int i;
1194 struct target_aux_context *aux =
1195 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1196
1197 /* set up the stack frame for unwinding */
1198 __put_user(env->xregs[29], &sf->fp);
1199 __put_user(env->xregs[30], &sf->lr);
1200
1201 for (i = 0; i < 31; i++) {
1202 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1203 }
1204 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1205 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001206 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001207
Peter Maydell7af03922014-05-01 18:36:17 +01001208 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001209
1210 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1211 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1212 }
1213
1214 for (i = 0; i < 32; i++) {
1215#ifdef TARGET_WORDS_BIGENDIAN
1216 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1217 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1218#else
1219 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1220 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1221#endif
1222 }
Will Newtone0ee1382014-01-04 22:15:48 +00001223 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1224 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001225 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1226 __put_user(sizeof(struct target_fpsimd_context),
1227 &aux->fpsimd.head.size);
1228
1229 /* set the "end" magic */
1230 __put_user(0, &aux->end.magic);
1231 __put_user(0, &aux->end.size);
1232
1233 return 0;
1234}
1235
1236static int target_restore_sigframe(CPUARMState *env,
1237 struct target_rt_sigframe *sf)
1238{
1239 sigset_t set;
1240 int i;
1241 struct target_aux_context *aux =
1242 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001243 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001244 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001245
1246 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001247 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001248
1249 for (i = 0; i < 31; i++) {
1250 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1251 }
1252
1253 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1254 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001255 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1256 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001257
1258 __get_user(magic, &aux->fpsimd.head.magic);
1259 __get_user(size, &aux->fpsimd.head.size);
1260
1261 if (magic != TARGET_FPSIMD_MAGIC
1262 || size != sizeof(struct target_fpsimd_context)) {
1263 return 1;
1264 }
1265
Peter Maydell4cf23482014-03-02 19:36:38 +00001266 for (i = 0; i < 32; i++) {
1267#ifdef TARGET_WORDS_BIGENDIAN
1268 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1269 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1270#else
1271 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1272 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1273#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001274 }
Will Newtone0ee1382014-01-04 22:15:48 +00001275 __get_user(fpsr, &aux->fpsimd.fpsr);
1276 vfp_set_fpsr(env, fpsr);
1277 __get_user(fpcr, &aux->fpsimd.fpcr);
1278 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001279
1280 return 0;
1281}
1282
1283static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1284{
1285 abi_ulong sp;
1286
1287 sp = env->xregs[31];
1288
1289 /*
1290 * This is the X/Open sanctioned signal stack switching.
1291 */
Riku Voipiob545f632014-07-15 17:01:55 +03001292 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001293 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1294 }
1295
1296 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1297
1298 return sp;
1299}
1300
1301static void target_setup_frame(int usig, struct target_sigaction *ka,
1302 target_siginfo_t *info, target_sigset_t *set,
1303 CPUARMState *env)
1304{
1305 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001306 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001307
1308 frame_addr = get_sigframe(ka, env);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001309 trace_user_setup_frame(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001310 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1311 goto give_sigsegv;
1312 }
1313
1314 __put_user(0, &frame->uc.tuc_flags);
1315 __put_user(0, &frame->uc.tuc_link);
1316
1317 __put_user(target_sigaltstack_used.ss_sp,
1318 &frame->uc.tuc_stack.ss_sp);
1319 __put_user(sas_ss_flags(env->xregs[31]),
1320 &frame->uc.tuc_stack.ss_flags);
1321 __put_user(target_sigaltstack_used.ss_size,
1322 &frame->uc.tuc_stack.ss_size);
1323 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001324 if (ka->sa_flags & TARGET_SA_RESTORER) {
1325 return_addr = ka->sa_restorer;
1326 } else {
1327 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1328 __put_user(0xd2801168, &frame->tramp[0]);
1329 __put_user(0xd4000001, &frame->tramp[1]);
1330 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1331 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001332 env->xregs[0] = usig;
1333 env->xregs[31] = frame_addr;
1334 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1335 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001336 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001337 if (info) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00001338 tswap_siginfo(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001339 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1340 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1341 }
1342
1343 unlock_user_struct(frame, frame_addr, 1);
1344 return;
1345
1346 give_sigsegv:
1347 unlock_user_struct(frame, frame_addr, 1);
1348 force_sig(TARGET_SIGSEGV);
1349}
1350
1351static void setup_rt_frame(int sig, struct target_sigaction *ka,
1352 target_siginfo_t *info, target_sigset_t *set,
1353 CPUARMState *env)
1354{
1355 target_setup_frame(sig, ka, info, set, env);
1356}
1357
1358static void setup_frame(int sig, struct target_sigaction *ka,
1359 target_sigset_t *set, CPUARMState *env)
1360{
1361 target_setup_frame(sig, ka, 0, set, env);
1362}
1363
1364long do_rt_sigreturn(CPUARMState *env)
1365{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001366 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001367 abi_ulong frame_addr = env->xregs[31];
1368
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001369 trace_user_do_rt_sigreturn(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001370 if (frame_addr & 15) {
1371 goto badframe;
1372 }
1373
1374 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1375 goto badframe;
1376 }
1377
1378 if (target_restore_sigframe(env, frame)) {
1379 goto badframe;
1380 }
1381
1382 if (do_sigaltstack(frame_addr +
1383 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1384 0, get_sp_from_cpustate(env)) == -EFAULT) {
1385 goto badframe;
1386 }
1387
1388 unlock_user_struct(frame, frame_addr, 0);
1389 return env->xregs[0];
1390
1391 badframe:
1392 unlock_user_struct(frame, frame_addr, 0);
1393 force_sig(TARGET_SIGSEGV);
1394 return 0;
1395}
1396
1397long do_sigreturn(CPUARMState *env)
1398{
1399 return do_rt_sigreturn(env);
1400}
1401
bellard43fff232003-07-09 19:31:39 +00001402#elif defined(TARGET_ARM)
1403
1404struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001405 abi_ulong trap_no;
1406 abi_ulong error_code;
1407 abi_ulong oldmask;
1408 abi_ulong arm_r0;
1409 abi_ulong arm_r1;
1410 abi_ulong arm_r2;
1411 abi_ulong arm_r3;
1412 abi_ulong arm_r4;
1413 abi_ulong arm_r5;
1414 abi_ulong arm_r6;
1415 abi_ulong arm_r7;
1416 abi_ulong arm_r8;
1417 abi_ulong arm_r9;
1418 abi_ulong arm_r10;
1419 abi_ulong arm_fp;
1420 abi_ulong arm_ip;
1421 abi_ulong arm_sp;
1422 abi_ulong arm_lr;
1423 abi_ulong arm_pc;
1424 abi_ulong arm_cpsr;
1425 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001426};
1427
pbrooka745ec62008-05-06 15:36:17 +00001428struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001429 abi_ulong tuc_flags;
1430 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001431 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001432 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001433 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001434};
1435
pbrooka745ec62008-05-06 15:36:17 +00001436struct target_ucontext_v2 {
1437 abi_ulong tuc_flags;
1438 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001439 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001440 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001441 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001442 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001443 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1444};
1445
Peter Maydell0d871bd2010-11-24 15:20:05 +00001446struct target_user_vfp {
1447 uint64_t fpregs[32];
1448 abi_ulong fpscr;
1449};
1450
1451struct target_user_vfp_exc {
1452 abi_ulong fpexc;
1453 abi_ulong fpinst;
1454 abi_ulong fpinst2;
1455};
1456
1457struct target_vfp_sigframe {
1458 abi_ulong magic;
1459 abi_ulong size;
1460 struct target_user_vfp ufp;
1461 struct target_user_vfp_exc ufp_exc;
1462} __attribute__((__aligned__(8)));
1463
Peter Maydell08e11252010-11-24 15:20:07 +00001464struct target_iwmmxt_sigframe {
1465 abi_ulong magic;
1466 abi_ulong size;
1467 uint64_t regs[16];
1468 /* Note that not all the coprocessor control registers are stored here */
1469 uint32_t wcssf;
1470 uint32_t wcasf;
1471 uint32_t wcgr0;
1472 uint32_t wcgr1;
1473 uint32_t wcgr2;
1474 uint32_t wcgr3;
1475} __attribute__((__aligned__(8)));
1476
Peter Maydell0d871bd2010-11-24 15:20:05 +00001477#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001478#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001479
pbrooka8c33202008-05-07 23:22:46 +00001480struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001481{
1482 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001483 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1484 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001485};
1486
pbrooka8c33202008-05-07 23:22:46 +00001487struct sigframe_v2
1488{
1489 struct target_ucontext_v2 uc;
1490 abi_ulong retcode;
1491};
1492
pbrooka745ec62008-05-06 15:36:17 +00001493struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001494{
bellardf8b0aa22007-11-11 23:03:42 +00001495 abi_ulong pinfo;
1496 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001497 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001498 struct target_ucontext_v1 uc;
1499 abi_ulong retcode;
1500};
1501
1502struct rt_sigframe_v2
1503{
1504 struct target_siginfo info;
1505 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001506 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001507};
1508
1509#define TARGET_CONFIG_CPU_32 1
1510
1511/*
1512 * For ARM syscalls, we encode the syscall number into the instruction.
1513 */
1514#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1515#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1516
1517/*
1518 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1519 * need two 16-bit instructions.
1520 */
1521#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1522#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1523
blueswir1992f48a2007-10-14 16:27:31 +00001524static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001525 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1526 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1527};
1528
1529
Andreas Färber05390242012-02-25 03:37:53 +01001530static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001531{
1532 return 1;
1533}
1534
pbrooka8c33202008-05-07 23:22:46 +00001535static void
bellard43fff232003-07-09 19:31:39 +00001536setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001537 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001538{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001539 __put_user(env->regs[0], &sc->arm_r0);
1540 __put_user(env->regs[1], &sc->arm_r1);
1541 __put_user(env->regs[2], &sc->arm_r2);
1542 __put_user(env->regs[3], &sc->arm_r3);
1543 __put_user(env->regs[4], &sc->arm_r4);
1544 __put_user(env->regs[5], &sc->arm_r5);
1545 __put_user(env->regs[6], &sc->arm_r6);
1546 __put_user(env->regs[7], &sc->arm_r7);
1547 __put_user(env->regs[8], &sc->arm_r8);
1548 __put_user(env->regs[9], &sc->arm_r9);
1549 __put_user(env->regs[10], &sc->arm_r10);
1550 __put_user(env->regs[11], &sc->arm_fp);
1551 __put_user(env->regs[12], &sc->arm_ip);
1552 __put_user(env->regs[13], &sc->arm_sp);
1553 __put_user(env->regs[14], &sc->arm_lr);
1554 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001555#ifdef TARGET_CONFIG_CPU_32
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001556 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001557#endif
1558
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001559 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1560 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1561 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1562 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001563}
1564
bellard579a97f2007-11-11 14:26:47 +00001565static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001566get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001567{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001568 unsigned long sp = regs->regs[13];
bellard43fff232003-07-09 19:31:39 +00001569
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001570 /*
1571 * This is the X/Open sanctioned signal stack switching.
1572 */
1573 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
1574 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1575 }
1576 /*
1577 * ATPCS B01 mandates 8-byte alignment
1578 */
1579 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001580}
1581
Riku Voipio0188fad2014-04-23 13:34:15 +03001582static void
Andreas Färber05390242012-02-25 03:37:53 +01001583setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001584 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001585{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001586 abi_ulong handler = ka->_sa_handler;
1587 abi_ulong retcode;
1588 int thumb = handler & 1;
1589 uint32_t cpsr = cpsr_read(env);
Peter Maydell964413d2011-01-14 20:39:19 +01001590
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001591 cpsr &= ~CPSR_IT;
1592 if (thumb) {
1593 cpsr |= CPSR_T;
1594 } else {
1595 cpsr &= ~CPSR_T;
1596 }
bellard43fff232003-07-09 19:31:39 +00001597
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001598 if (ka->sa_flags & TARGET_SA_RESTORER) {
1599 retcode = ka->sa_restorer;
1600 } else {
1601 unsigned int idx = thumb;
bellard43fff232003-07-09 19:31:39 +00001602
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001603 if (ka->sa_flags & TARGET_SA_SIGINFO) {
1604 idx += 2;
1605 }
bellard43fff232003-07-09 19:31:39 +00001606
Riku Voipio0188fad2014-04-23 13:34:15 +03001607 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001608
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001609 retcode = rc_addr + thumb;
1610 }
bellard43fff232003-07-09 19:31:39 +00001611
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001612 env->regs[0] = usig;
1613 env->regs[13] = frame_addr;
1614 env->regs[14] = retcode;
1615 env->regs[15] = handler & (thumb ? ~1 : ~3);
1616 cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001617}
1618
Andreas Färber05390242012-02-25 03:37:53 +01001619static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001620{
1621 int i;
1622 struct target_vfp_sigframe *vfpframe;
1623 vfpframe = (struct target_vfp_sigframe *)regspace;
1624 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1625 __put_user(sizeof(*vfpframe), &vfpframe->size);
1626 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001627 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001628 }
1629 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1630 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1631 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1632 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1633 return (abi_ulong*)(vfpframe+1);
1634}
1635
Andreas Färber05390242012-02-25 03:37:53 +01001636static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1637 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001638{
1639 int i;
1640 struct target_iwmmxt_sigframe *iwmmxtframe;
1641 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1642 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1643 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1644 for (i = 0; i < 16; i++) {
1645 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1646 }
1647 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1648 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1649 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1650 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1651 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1652 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1653 return (abi_ulong*)(iwmmxtframe+1);
1654}
1655
pbrooka8c33202008-05-07 23:22:46 +00001656static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001657 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001658{
pbrooka8c33202008-05-07 23:22:46 +00001659 struct target_sigaltstack stack;
1660 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001661 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001662
1663 /* Clear all the bits of the ucontext we don't use. */
1664 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1665
1666 memset(&stack, 0, sizeof(stack));
1667 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1668 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1669 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1670 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1671
1672 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001673 /* Save coprocessor signal frame. */
1674 regspace = uc->tuc_regspace;
1675 if (arm_feature(env, ARM_FEATURE_VFP)) {
1676 regspace = setup_sigframe_v2_vfp(regspace, env);
1677 }
Peter Maydell08e11252010-11-24 15:20:07 +00001678 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1679 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1680 }
1681
Peter Maydell0d871bd2010-11-24 15:20:05 +00001682 /* Write terminating magic word */
1683 __put_user(0, regspace);
1684
pbrooka8c33202008-05-07 23:22:46 +00001685 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1686 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1687 }
1688}
1689
1690/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001691static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001692 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001693{
1694 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001695 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001696 int i;
bellard43fff232003-07-09 19:31:39 +00001697
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001698 trace_user_setup_frame(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001699 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1700 return;
1701
pbrooka8c33202008-05-07 23:22:46 +00001702 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001703
Riku Voipio0188fad2014-04-23 13:34:15 +03001704 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1705 __put_user(set->sig[i], &frame->extramask[i - 1]);
1706 }
bellard43fff232003-07-09 19:31:39 +00001707
pbrooka8c33202008-05-07 23:22:46 +00001708 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1709 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001710
bellard579a97f2007-11-11 14:26:47 +00001711 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001712}
1713
pbrook624f7972008-05-31 16:11:38 +00001714static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001715 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001716{
1717 struct sigframe_v2 *frame;
1718 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1719
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001720 trace_user_setup_frame(regs, frame_addr);
pbrooka8c33202008-05-07 23:22:46 +00001721 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1722 return;
1723
1724 setup_sigframe_v2(&frame->uc, set, regs);
1725
1726 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1727 frame_addr + offsetof(struct sigframe_v2, retcode));
1728
1729 unlock_user_struct(frame, frame_addr, 1);
1730}
1731
pbrook624f7972008-05-31 16:11:38 +00001732static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001733 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001734{
1735 if (get_osversion() >= 0x020612) {
1736 setup_frame_v2(usig, ka, set, regs);
1737 } else {
1738 setup_frame_v1(usig, ka, set, regs);
1739 }
bellard43fff232003-07-09 19:31:39 +00001740}
1741
bellard579a97f2007-11-11 14:26:47 +00001742/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001743static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001744 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001745 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001746{
pbrooka745ec62008-05-06 15:36:17 +00001747 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001748 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001749 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001750 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001751 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001752
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001753 trace_user_setup_rt_frame(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001754 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001755 return /* 1 */;
1756
pbrooka745ec62008-05-06 15:36:17 +00001757 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001758 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001759 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001760 __put_user(uc_addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001761 tswap_siginfo(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001762
1763 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001764 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001765
thsa04e1342007-09-27 13:57:58 +00001766 memset(&stack, 0, sizeof(stack));
1767 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1768 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1769 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001770 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001771
pbrooka8c33202008-05-07 23:22:46 +00001772 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001773 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03001774 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
bellard92319442004-06-19 16:58:13 +00001775 }
bellard43fff232003-07-09 19:31:39 +00001776
pbrooka8c33202008-05-07 23:22:46 +00001777 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1778 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001779
pbrooka8c33202008-05-07 23:22:46 +00001780 env->regs[1] = info_addr;
1781 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001782
pbrooka745ec62008-05-06 15:36:17 +00001783 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001784}
1785
pbrook624f7972008-05-31 16:11:38 +00001786static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001787 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001788 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001789{
1790 struct rt_sigframe_v2 *frame;
1791 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001792 abi_ulong info_addr, uc_addr;
1793
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001794 trace_user_setup_rt_frame(env, frame_addr);
pbrooka745ec62008-05-06 15:36:17 +00001795 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1796 return /* 1 */;
1797
1798 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1799 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001800 tswap_siginfo(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001801
pbrooka8c33202008-05-07 23:22:46 +00001802 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001803
pbrooka8c33202008-05-07 23:22:46 +00001804 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1805 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001806
pbrooka8c33202008-05-07 23:22:46 +00001807 env->regs[1] = info_addr;
1808 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001809
bellard579a97f2007-11-11 14:26:47 +00001810 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001811}
1812
pbrook624f7972008-05-31 16:11:38 +00001813static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001814 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001815 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001816{
1817 if (get_osversion() >= 0x020612) {
1818 setup_rt_frame_v2(usig, ka, info, set, env);
1819 } else {
1820 setup_rt_frame_v1(usig, ka, info, set, env);
1821 }
1822}
1823
bellard43fff232003-07-09 19:31:39 +00001824static int
Andreas Färber05390242012-02-25 03:37:53 +01001825restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001826{
1827 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001828 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001829
Riku Voipio1d8b5122014-04-23 10:26:05 +03001830 __get_user(env->regs[0], &sc->arm_r0);
1831 __get_user(env->regs[1], &sc->arm_r1);
1832 __get_user(env->regs[2], &sc->arm_r2);
1833 __get_user(env->regs[3], &sc->arm_r3);
1834 __get_user(env->regs[4], &sc->arm_r4);
1835 __get_user(env->regs[5], &sc->arm_r5);
1836 __get_user(env->regs[6], &sc->arm_r6);
1837 __get_user(env->regs[7], &sc->arm_r7);
1838 __get_user(env->regs[8], &sc->arm_r8);
1839 __get_user(env->regs[9], &sc->arm_r9);
1840 __get_user(env->regs[10], &sc->arm_r10);
1841 __get_user(env->regs[11], &sc->arm_fp);
1842 __get_user(env->regs[12], &sc->arm_ip);
1843 __get_user(env->regs[13], &sc->arm_sp);
1844 __get_user(env->regs[14], &sc->arm_lr);
1845 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001846#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001847 __get_user(cpsr, &sc->arm_cpsr);
Peter Maydell50866ba2016-02-23 15:36:43 +00001848 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001849#endif
1850
1851 err |= !valid_user_regs(env);
1852
1853 return err;
1854}
1855
Andreas Färber05390242012-02-25 03:37:53 +01001856static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001857{
bellardf8b0aa22007-11-11 23:03:42 +00001858 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001859 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001860 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001861 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001862 int i;
bellard43fff232003-07-09 19:31:39 +00001863
1864 /*
1865 * Since we stacked the signal on a 64-bit boundary,
1866 * then 'sp' should be word aligned here. If it's
1867 * not, then the user is trying to mess with us.
1868 */
bellardf8b0aa22007-11-11 23:03:42 +00001869 frame_addr = env->regs[13];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001870 trace_user_do_sigreturn(env, frame_addr);
Peter Maydell978fae92013-07-29 12:00:32 +01001871 if (frame_addr & 7) {
1872 goto badframe;
1873 }
1874
bellardf8b0aa22007-11-11 23:03:42 +00001875 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1876 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001877
Riku Voipiof5f601a2014-04-23 13:00:17 +03001878 __get_user(set.sig[0], &frame->sc.oldmask);
1879 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1880 __get_user(set.sig[i], &frame->extramask[i - 1]);
1881 }
bellard43fff232003-07-09 19:31:39 +00001882
bellard92319442004-06-19 16:58:13 +00001883 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001884 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001885
1886 if (restore_sigcontext(env, &frame->sc))
1887 goto badframe;
1888
1889#if 0
1890 /* Send SIGTRAP if we're single-stepping */
1891 if (ptrace_cancel_bpt(current))
1892 send_sig(SIGTRAP, current, 1);
1893#endif
bellardf8b0aa22007-11-11 23:03:42 +00001894 unlock_user_struct(frame, frame_addr, 0);
1895 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001896
1897badframe:
Riku Voipio66393fb2009-12-04 15:16:32 +02001898 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001899 return 0;
1900}
1901
Andreas Färber05390242012-02-25 03:37:53 +01001902static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001903{
1904 int i;
1905 abi_ulong magic, sz;
1906 uint32_t fpscr, fpexc;
1907 struct target_vfp_sigframe *vfpframe;
1908 vfpframe = (struct target_vfp_sigframe *)regspace;
1909
1910 __get_user(magic, &vfpframe->magic);
1911 __get_user(sz, &vfpframe->size);
1912 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1913 return 0;
1914 }
1915 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001916 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001917 }
1918 __get_user(fpscr, &vfpframe->ufp.fpscr);
1919 vfp_set_fpscr(env, fpscr);
1920 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1921 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1922 * and the exception flag is cleared
1923 */
1924 fpexc |= (1 << 30);
1925 fpexc &= ~((1 << 31) | (1 << 28));
1926 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1927 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1928 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1929 return (abi_ulong*)(vfpframe + 1);
1930}
1931
Andreas Färber05390242012-02-25 03:37:53 +01001932static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1933 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001934{
1935 int i;
1936 abi_ulong magic, sz;
1937 struct target_iwmmxt_sigframe *iwmmxtframe;
1938 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1939
1940 __get_user(magic, &iwmmxtframe->magic);
1941 __get_user(sz, &iwmmxtframe->size);
1942 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1943 return 0;
1944 }
1945 for (i = 0; i < 16; i++) {
1946 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1947 }
1948 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1949 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1950 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1951 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1952 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1953 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1954 return (abi_ulong*)(iwmmxtframe + 1);
1955}
1956
Andreas Färber05390242012-02-25 03:37:53 +01001957static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001958 struct target_ucontext_v2 *uc)
1959{
1960 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001961 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001962
1963 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001964 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001965
1966 if (restore_sigcontext(env, &uc->tuc_mcontext))
1967 return 1;
1968
Peter Maydell5f9099d2010-11-24 15:20:06 +00001969 /* Restore coprocessor signal frame */
1970 regspace = uc->tuc_regspace;
1971 if (arm_feature(env, ARM_FEATURE_VFP)) {
1972 regspace = restore_sigframe_v2_vfp(env, regspace);
1973 if (!regspace) {
1974 return 1;
1975 }
1976 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001977 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1978 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1979 if (!regspace) {
1980 return 1;
1981 }
1982 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001983
pbrooka8c33202008-05-07 23:22:46 +00001984 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1985 return 1;
1986
1987#if 0
1988 /* Send SIGTRAP if we're single-stepping */
1989 if (ptrace_cancel_bpt(current))
1990 send_sig(SIGTRAP, current, 1);
1991#endif
1992
1993 return 0;
1994}
1995
Andreas Färber05390242012-02-25 03:37:53 +01001996static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001997{
1998 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001999 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002000
2001 /*
2002 * Since we stacked the signal on a 64-bit boundary,
2003 * then 'sp' should be word aligned here. If it's
2004 * not, then the user is trying to mess with us.
2005 */
pbrooka8c33202008-05-07 23:22:46 +00002006 frame_addr = env->regs[13];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002007 trace_user_do_sigreturn(env, frame_addr);
Peter Maydell978fae92013-07-29 12:00:32 +01002008 if (frame_addr & 7) {
2009 goto badframe;
2010 }
2011
pbrooka8c33202008-05-07 23:22:46 +00002012 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2013 goto badframe;
2014
2015 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2016 goto badframe;
2017
2018 unlock_user_struct(frame, frame_addr, 0);
2019 return env->regs[0];
2020
2021badframe:
2022 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002023 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002024 return 0;
2025}
2026
Andreas Färber05390242012-02-25 03:37:53 +01002027long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002028{
2029 if (get_osversion() >= 0x020612) {
2030 return do_sigreturn_v2(env);
2031 } else {
2032 return do_sigreturn_v1(env);
2033 }
2034}
2035
Andreas Färber05390242012-02-25 03:37:53 +01002036static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002037{
bellardf8b0aa22007-11-11 23:03:42 +00002038 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002039 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002040 sigset_t host_set;
2041
2042 /*
2043 * Since we stacked the signal on a 64-bit boundary,
2044 * then 'sp' should be word aligned here. If it's
2045 * not, then the user is trying to mess with us.
2046 */
bellardf8b0aa22007-11-11 23:03:42 +00002047 frame_addr = env->regs[13];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002048 trace_user_do_rt_sigreturn(env, frame_addr);
Peter Maydell978fae92013-07-29 12:00:32 +01002049 if (frame_addr & 7) {
2050 goto badframe;
2051 }
2052
bellardf8b0aa22007-11-11 23:03:42 +00002053 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2054 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002055
bellardb8076a72005-04-07 22:20:31 +00002056 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002057 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002058
bellardb8076a72005-04-07 22:20:31 +00002059 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002060 goto badframe;
2061
pbrooka745ec62008-05-06 15:36:17 +00002062 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 +00002063 goto badframe;
2064
bellard43fff232003-07-09 19:31:39 +00002065#if 0
2066 /* Send SIGTRAP if we're single-stepping */
2067 if (ptrace_cancel_bpt(current))
2068 send_sig(SIGTRAP, current, 1);
2069#endif
bellardf8b0aa22007-11-11 23:03:42 +00002070 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002071 return env->regs[0];
2072
2073badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002074 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002075 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002076 return 0;
2077}
2078
Andreas Färber05390242012-02-25 03:37:53 +01002079static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002080{
2081 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002082 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002083
2084 /*
2085 * Since we stacked the signal on a 64-bit boundary,
2086 * then 'sp' should be word aligned here. If it's
2087 * not, then the user is trying to mess with us.
2088 */
pbrooka745ec62008-05-06 15:36:17 +00002089 frame_addr = env->regs[13];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002090 trace_user_do_rt_sigreturn(env, frame_addr);
Peter Maydell978fae92013-07-29 12:00:32 +01002091 if (frame_addr & 7) {
2092 goto badframe;
2093 }
2094
pbrooka745ec62008-05-06 15:36:17 +00002095 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2096 goto badframe;
2097
pbrooka8c33202008-05-07 23:22:46 +00002098 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2099 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002100
pbrooka745ec62008-05-06 15:36:17 +00002101 unlock_user_struct(frame, frame_addr, 0);
2102 return env->regs[0];
2103
2104badframe:
2105 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002106 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002107 return 0;
2108}
2109
Andreas Färber05390242012-02-25 03:37:53 +01002110long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002111{
2112 if (get_osversion() >= 0x020612) {
2113 return do_rt_sigreturn_v2(env);
2114 } else {
2115 return do_rt_sigreturn_v1(env);
2116 }
2117}
2118
bellard6d5e2162004-09-30 22:04:13 +00002119#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002120
bellard6d5e2162004-09-30 22:04:13 +00002121#define __SUNOS_MAXWIN 31
2122
2123/* This is what SunOS does, so shall I. */
2124struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002125 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002126
blueswir1992f48a2007-10-14 16:27:31 +00002127 abi_ulong sigc_mask; /* sigmask to restore */
2128 abi_ulong sigc_sp; /* stack pointer */
2129 abi_ulong sigc_pc; /* program counter */
2130 abi_ulong sigc_npc; /* next program counter */
2131 abi_ulong sigc_psr; /* for condition codes etc */
2132 abi_ulong sigc_g1; /* User uses these two registers */
2133 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002134
2135 /* Now comes information regarding the users window set
2136 * at the time of the signal.
2137 */
blueswir1992f48a2007-10-14 16:27:31 +00002138 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002139
2140 /* stack ptrs for each regwin buf */
2141 char *sigc_spbuf[__SUNOS_MAXWIN];
2142
2143 /* Windows to restore after signal */
2144 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002145 abi_ulong locals[8];
2146 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002147 } sigc_wbuf[__SUNOS_MAXWIN];
2148};
2149/* A Sparc stack frame */
2150struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002151 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002152 abi_ulong ins[8];
2153 /* It's simpler to treat fp and callers_pc as elements of ins[]
2154 * since we never need to access them ourselves.
2155 */
bellard6d5e2162004-09-30 22:04:13 +00002156 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002157 abi_ulong xargs[6];
2158 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002159};
2160
2161typedef struct {
2162 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002163 abi_ulong psr;
2164 abi_ulong pc;
2165 abi_ulong npc;
2166 abi_ulong y;
2167 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002168 } si_regs;
2169 int si_mask;
2170} __siginfo_t;
2171
2172typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002173 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002174 unsigned long si_fsr;
2175 unsigned long si_fpqdepth;
2176 struct {
2177 unsigned long *insn_addr;
2178 unsigned long insn;
2179 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002180} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002181
2182
2183struct target_signal_frame {
2184 struct sparc_stackf ss;
2185 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002186 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002187 abi_ulong insns[2] __attribute__ ((aligned (8)));
2188 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2189 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002190 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002191};
2192struct target_rt_signal_frame {
2193 struct sparc_stackf ss;
2194 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002195 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002196 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002197 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002198 unsigned int insns[2];
2199 stack_t stack;
2200 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002201 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002202};
2203
bellarde80cfcf2004-12-19 23:18:01 +00002204#define UREG_O0 16
2205#define UREG_O6 22
2206#define UREG_I0 0
2207#define UREG_I1 1
2208#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002209#define UREG_I3 3
2210#define UREG_I4 4
2211#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002212#define UREG_I6 6
2213#define UREG_I7 7
2214#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002215#define UREG_FP UREG_I6
2216#define UREG_SP UREG_O6
2217
pbrook624f7972008-05-31 16:11:38 +00002218static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002219 CPUSPARCState *env,
2220 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002221{
bellard459a4012007-11-11 19:45:10 +00002222 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002223
2224 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002225
2226 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002227 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002228 if (!on_sig_stack(sp)
2229 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2230 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002231 }
bellard459a4012007-11-11 19:45:10 +00002232 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002233}
2234
2235static int
Andreas Färber05390242012-02-25 03:37:53 +01002236setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002237{
2238 int err = 0, i;
2239
Riku Voipio1d8b5122014-04-23 10:26:05 +03002240 __put_user(env->psr, &si->si_regs.psr);
2241 __put_user(env->pc, &si->si_regs.pc);
2242 __put_user(env->npc, &si->si_regs.npc);
2243 __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002244 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002245 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
bellard6d5e2162004-09-30 22:04:13 +00002246 }
bellarda315a142005-01-30 22:59:18 +00002247 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002248 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002249 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002250 __put_user(mask, &si->si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002251 return err;
2252}
bellarde80cfcf2004-12-19 23:18:01 +00002253
bellard80a9d032005-01-03 23:31:27 +00002254#if 0
bellard6d5e2162004-09-30 22:04:13 +00002255static int
2256setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002257 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002258{
2259 int err = 0;
2260
Riku Voipio1d8b5122014-04-23 10:26:05 +03002261 __put_user(mask, &sc->sigc_mask);
2262 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2263 __put_user(env->pc, &sc->sigc_pc);
2264 __put_user(env->npc, &sc->sigc_npc);
2265 __put_user(env->psr, &sc->sigc_psr);
2266 __put_user(env->gregs[1], &sc->sigc_g1);
2267 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002268
2269 return err;
2270}
bellard80a9d032005-01-03 23:31:27 +00002271#endif
bellard6d5e2162004-09-30 22:04:13 +00002272#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2273
pbrook624f7972008-05-31 16:11:38 +00002274static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002275 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002276{
bellard459a4012007-11-11 19:45:10 +00002277 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002278 struct target_signal_frame *sf;
2279 int sigframe_size, err, i;
2280
2281 /* 1. Make sure everything is clean */
2282 //synchronize_user_stack();
2283
2284 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002285 sf_addr = get_sigframe(ka, env, sigframe_size);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002286 trace_user_setup_frame(env, sf_addr);
bellard6d5e2162004-09-30 22:04:13 +00002287
bellard459a4012007-11-11 19:45:10 +00002288 sf = lock_user(VERIFY_WRITE, sf_addr,
2289 sizeof(struct target_signal_frame), 0);
2290 if (!sf)
2291 goto sigsegv;
2292
bellard6d5e2162004-09-30 22:04:13 +00002293#if 0
2294 if (invalid_frame_pointer(sf, sigframe_size))
2295 goto sigill_and_return;
2296#endif
2297 /* 2. Save the current process state */
2298 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002299 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002300
Riku Voipio1d8b5122014-04-23 10:26:05 +03002301 //save_fpu_state(regs, &sf->fpu_state);
2302 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002303
Riku Voipio1d8b5122014-04-23 10:26:05 +03002304 __put_user(set->sig[0], &sf->info.si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002305 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002306 __put_user(set->sig[i + 1], &sf->extramask[i]);
bellard6d5e2162004-09-30 22:04:13 +00002307 }
2308
bellarda315a142005-01-30 22:59:18 +00002309 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002310 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002311 }
bellarda315a142005-01-30 22:59:18 +00002312 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002313 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002314 }
bellard6d5e2162004-09-30 22:04:13 +00002315 if (err)
2316 goto sigsegv;
2317
2318 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002319 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002320 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002321 env->regwptr[UREG_I1] = sf_addr +
2322 offsetof(struct target_signal_frame, info);
2323 env->regwptr[UREG_I2] = sf_addr +
2324 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002325
2326 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002327 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002328 env->npc = (env->pc + 4);
2329 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002330 if (ka->sa_restorer)
2331 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002332 else {
bellard775b58d2007-11-11 16:22:17 +00002333 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002334
2335 env->regwptr[UREG_I7] = sf_addr +
2336 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002337
2338 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002339 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002340 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002341
2342 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002343 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002344 __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002345 if (err)
2346 goto sigsegv;
2347
2348 /* Flush instruction space. */
2349 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
Peter Crosthwaitebbd77c12015-06-23 19:31:15 -07002350 // tb_flush(CPU(sparc_env_get_cpu(env)));
bellard6d5e2162004-09-30 22:04:13 +00002351 }
bellard459a4012007-11-11 19:45:10 +00002352 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002353 return;
bellard459a4012007-11-11 19:45:10 +00002354#if 0
2355sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002356 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002357#endif
bellard6d5e2162004-09-30 22:04:13 +00002358sigsegv:
bellard459a4012007-11-11 19:45:10 +00002359 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002360 force_sig(TARGET_SIGSEGV);
2361}
bellard6d5e2162004-09-30 22:04:13 +00002362
pbrook624f7972008-05-31 16:11:38 +00002363static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002364 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002365 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002366{
2367 fprintf(stderr, "setup_rt_frame: not implemented\n");
2368}
2369
Andreas Färber05390242012-02-25 03:37:53 +01002370long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002371{
bellardf8b0aa22007-11-11 23:03:42 +00002372 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002373 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002374 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002375 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002376 sigset_t host_set;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002377 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002378
bellardf8b0aa22007-11-11 23:03:42 +00002379 sf_addr = env->regwptr[UREG_FP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002380 trace_user_do_sigreturn(env, sf_addr);
bellardf8b0aa22007-11-11 23:03:42 +00002381 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2382 goto segv_and_exit;
bellard6d5e2162004-09-30 22:04:13 +00002383
2384 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002385
bellardf8b0aa22007-11-11 23:03:42 +00002386 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002387 goto segv_and_exit;
2388
Riku Voipio1d8b5122014-04-23 10:26:05 +03002389 __get_user(pc, &sf->info.si_regs.pc);
2390 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002391
bellard6d5e2162004-09-30 22:04:13 +00002392 if ((pc | npc) & 3)
2393 goto segv_and_exit;
2394
2395 /* 2. Restore the state */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002396 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002397
bellard6d5e2162004-09-30 22:04:13 +00002398 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002399 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2400 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2401
2402 env->pc = pc;
2403 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002404 __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002405 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002406 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
bellarde80cfcf2004-12-19 23:18:01 +00002407 }
bellarda315a142005-01-30 22:59:18 +00002408 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002409 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
bellarde80cfcf2004-12-19 23:18:01 +00002410 }
bellard6d5e2162004-09-30 22:04:13 +00002411
Peter Maydell2aec3a22011-06-16 17:37:14 +01002412 /* FIXME: implement FPU save/restore:
2413 * __get_user(fpu_save, &sf->fpu_save);
2414 * if (fpu_save)
2415 * err |= restore_fpu_state(env, fpu_save);
2416 */
bellard6d5e2162004-09-30 22:04:13 +00002417
2418 /* This is pretty much atomic, no amount locking would prevent
2419 * the races which exist anyways.
2420 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002421 __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002422 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002423 __get_user(set.sig[i], &sf->extramask[i - 1]);
bellarde80cfcf2004-12-19 23:18:01 +00002424 }
2425
2426 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002427 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002428
2429 if (err)
2430 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002431 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002432 return env->regwptr[0];
2433
2434segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002435 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002436 force_sig(TARGET_SIGSEGV);
2437}
2438
Andreas Färber05390242012-02-25 03:37:53 +01002439long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002440{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002441 trace_user_do_rt_sigreturn(env, 0);
bellard6d5e2162004-09-30 22:04:13 +00002442 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002443 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002444}
2445
bellard459a4012007-11-11 19:45:10 +00002446#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002447#define MC_TSTATE 0
2448#define MC_PC 1
2449#define MC_NPC 2
2450#define MC_Y 3
2451#define MC_G1 4
2452#define MC_G2 5
2453#define MC_G3 6
2454#define MC_G4 7
2455#define MC_G5 8
2456#define MC_G6 9
2457#define MC_G7 10
2458#define MC_O0 11
2459#define MC_O1 12
2460#define MC_O2 13
2461#define MC_O3 14
2462#define MC_O4 15
2463#define MC_O5 16
2464#define MC_O6 17
2465#define MC_O7 18
2466#define MC_NGREG 19
2467
Anthony Liguoric227f092009-10-01 16:12:16 -05002468typedef abi_ulong target_mc_greg_t;
2469typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002470
2471struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002472 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002473 uint32_t mcfq_insn;
2474};
2475
2476struct target_mc_fpu {
2477 union {
2478 uint32_t sregs[32];
2479 uint64_t dregs[32];
2480 //uint128_t qregs[16];
2481 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002482 abi_ulong mcfpu_fsr;
2483 abi_ulong mcfpu_fprs;
2484 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002485 struct target_mc_fq *mcfpu_fq;
2486 unsigned char mcfpu_qcnt;
2487 unsigned char mcfpu_qentsz;
2488 unsigned char mcfpu_enab;
2489};
Anthony Liguoric227f092009-10-01 16:12:16 -05002490typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002491
2492typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002493 target_mc_gregset_t mc_gregs;
2494 target_mc_greg_t mc_fp;
2495 target_mc_greg_t mc_i7;
2496 target_mc_fpu_t mc_fpregs;
2497} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002498
2499struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002500 struct target_ucontext *tuc_link;
2501 abi_ulong tuc_flags;
2502 target_sigset_t tuc_sigmask;
2503 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002504};
2505
2506/* A V9 register window */
2507struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002508 abi_ulong locals[8];
2509 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002510};
2511
2512#define TARGET_STACK_BIAS 2047
2513
2514/* {set, get}context() needed for 64-bit SparcLinux userland. */
2515void sparc64_set_context(CPUSPARCState *env)
2516{
bellard459a4012007-11-11 19:45:10 +00002517 abi_ulong ucp_addr;
2518 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002519 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002520 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002521 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002522 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002523
bellard459a4012007-11-11 19:45:10 +00002524 ucp_addr = env->regwptr[UREG_I0];
2525 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2526 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002527 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002528 __get_user(pc, &((*grp)[MC_PC]));
2529 __get_user(npc, &((*grp)[MC_NPC]));
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002530 if ((pc | npc) & 3)
blueswir15bfb56b2007-10-05 17:01:51 +00002531 goto do_sigsegv;
2532 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002533 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002534 sigset_t set;
2535
2536 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002537 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002538 } else {
bellard459a4012007-11-11 19:45:10 +00002539 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002540 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002541 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002542 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002543 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002544 }
blueswir15bfb56b2007-10-05 17:01:51 +00002545 }
2546 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002547 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002548 }
2549 env->pc = pc;
2550 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002551 __get_user(env->y, &((*grp)[MC_Y]));
2552 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002553 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002554 cpu_put_ccr(env, tstate >> 32);
2555 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002556 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2557 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2558 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2559 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2560 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2561 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2562 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2563 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2564 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2565 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2566 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2567 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2568 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2569 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2570 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002571
Riku Voipio1d8b5122014-04-23 10:26:05 +03002572 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2573 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002574
bellard459a4012007-11-11 19:45:10 +00002575 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2576 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2577 abi_ulong) != 0)
2578 goto do_sigsegv;
2579 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2580 abi_ulong) != 0)
2581 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002582 /* FIXME this does not match how the kernel handles the FPU in
2583 * its sparc64_set_context implementation. In particular the FPU
2584 * is only restored if fenab is non-zero in:
2585 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2586 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002587 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002588 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002589 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2590 for (i = 0; i < 64; i++, src++) {
2591 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002592 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002593 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002594 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002595 }
2596 }
bellard459a4012007-11-11 19:45:10 +00002597 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002598 __get_user(env->fsr,
2599 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2600 __get_user(env->gsr,
2601 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002602 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002603 return;
2604 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002605 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002606 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002607}
2608
2609void sparc64_get_context(CPUSPARCState *env)
2610{
bellard459a4012007-11-11 19:45:10 +00002611 abi_ulong ucp_addr;
2612 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002613 target_mc_gregset_t *grp;
2614 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002615 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002616 int err;
2617 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002618 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002619 sigset_t set;
2620
bellard459a4012007-11-11 19:45:10 +00002621 ucp_addr = env->regwptr[UREG_I0];
2622 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2623 goto do_sigsegv;
2624
Aurelien Jarno60e99242010-03-29 02:12:51 +02002625 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002626 grp = &mcp->mc_gregs;
2627
2628 /* Skip over the trap instruction, first. */
2629 env->pc = env->npc;
2630 env->npc += 4;
2631
2632 err = 0;
2633
Alex Barcelo1c275922014-03-14 14:36:55 +00002634 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002635 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002636 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002637 __put_user(target_set.sig[0],
2638 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002639 } else {
2640 abi_ulong *src, *dst;
2641 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002642 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002643 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002644 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002645 }
blueswir15bfb56b2007-10-05 17:01:51 +00002646 if (err)
2647 goto do_sigsegv;
2648 }
2649
bellard459a4012007-11-11 19:45:10 +00002650 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002651 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2652 __put_user(env->pc, &((*grp)[MC_PC]));
2653 __put_user(env->npc, &((*grp)[MC_NPC]));
2654 __put_user(env->y, &((*grp)[MC_Y]));
2655 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2656 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2657 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2658 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2659 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2660 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2661 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2662 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2663 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2664 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2665 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2666 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2667 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2668 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2669 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002670
bellard459a4012007-11-11 19:45:10 +00002671 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2672 fp = i7 = 0;
2673 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2674 abi_ulong) != 0)
2675 goto do_sigsegv;
2676 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2677 abi_ulong) != 0)
2678 goto do_sigsegv;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002679 __put_user(fp, &(mcp->mc_fp));
2680 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002681
bellard459a4012007-11-11 19:45:10 +00002682 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002683 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2684 for (i = 0; i < 64; i++, dst++) {
2685 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002686 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002687 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002688 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002689 }
2690 }
bellard459a4012007-11-11 19:45:10 +00002691 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002692 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2693 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2694 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002695
2696 if (err)
2697 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002698 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002699 return;
2700 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002701 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002702 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002703}
2704#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002705#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002706
Richard Hendersonff970902013-02-10 10:30:42 -08002707# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002708struct target_sigcontext {
2709 uint32_t sc_regmask; /* Unused */
2710 uint32_t sc_status;
2711 uint64_t sc_pc;
2712 uint64_t sc_regs[32];
2713 uint64_t sc_fpregs[32];
2714 uint32_t sc_ownedfp; /* Unused */
2715 uint32_t sc_fpc_csr;
2716 uint32_t sc_fpc_eir; /* Unused */
2717 uint32_t sc_used_math;
2718 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002719 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002720 uint64_t sc_mdhi;
2721 uint64_t sc_mdlo;
2722 target_ulong sc_hi1; /* Was sc_cause */
2723 target_ulong sc_lo1; /* Was sc_badvaddr */
2724 target_ulong sc_hi2; /* Was sc_sigset[4] */
2725 target_ulong sc_lo2;
2726 target_ulong sc_hi3;
2727 target_ulong sc_lo3;
2728};
Richard Hendersonff970902013-02-10 10:30:42 -08002729# else /* N32 || N64 */
2730struct target_sigcontext {
2731 uint64_t sc_regs[32];
2732 uint64_t sc_fpregs[32];
2733 uint64_t sc_mdhi;
2734 uint64_t sc_hi1;
2735 uint64_t sc_hi2;
2736 uint64_t sc_hi3;
2737 uint64_t sc_mdlo;
2738 uint64_t sc_lo1;
2739 uint64_t sc_lo2;
2740 uint64_t sc_lo3;
2741 uint64_t sc_pc;
2742 uint32_t sc_fpc_csr;
2743 uint32_t sc_used_math;
2744 uint32_t sc_dsp;
2745 uint32_t sc_reserved;
2746};
2747# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002748
2749struct sigframe {
2750 uint32_t sf_ass[4]; /* argument save space for o32 */
2751 uint32_t sf_code[2]; /* signal trampoline */
2752 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002753 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002754};
2755
pbrook0b1bcb02009-04-21 01:41:10 +00002756struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002757 target_ulong tuc_flags;
2758 target_ulong tuc_link;
2759 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002760 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002761 struct target_sigcontext tuc_mcontext;
2762 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002763};
2764
2765struct target_rt_sigframe {
2766 uint32_t rs_ass[4]; /* argument save space for o32 */
2767 uint32_t rs_code[2]; /* signal trampoline */
2768 struct target_siginfo rs_info;
2769 struct target_ucontext rs_uc;
2770};
2771
bellard106ec872006-06-27 21:08:10 +00002772/* Install trampoline to jump back from signal handler */
2773static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2774{
Richard Henderson084d0492013-02-10 10:30:44 -08002775 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002776
2777 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002778 * Set up the return code ...
2779 *
2780 * li v0, __NR__foo_sigreturn
2781 * syscall
2782 */
bellard106ec872006-06-27 21:08:10 +00002783
Riku Voipio1d8b5122014-04-23 10:26:05 +03002784 __put_user(0x24020000 + syscall, tramp + 0);
2785 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002786 return err;
2787}
2788
Riku Voipio41ecc722014-04-23 11:01:00 +03002789static inline void setup_sigcontext(CPUMIPSState *regs,
2790 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002791{
Richard Henderson084d0492013-02-10 10:30:44 -08002792 int i;
bellard106ec872006-06-27 21:08:10 +00002793
Riku Voipio1d8b5122014-04-23 10:26:05 +03002794 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002795 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002796
Richard Henderson084d0492013-02-10 10:30:44 -08002797 __put_user(0, &sc->sc_regs[0]);
2798 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002799 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002800 }
bellard106ec872006-06-27 21:08:10 +00002801
Riku Voipio1d8b5122014-04-23 10:26:05 +03002802 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2803 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002804
Richard Henderson084d0492013-02-10 10:30:44 -08002805 /* Rather than checking for dsp existence, always copy. The storage
2806 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002807 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2808 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2809 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2810 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2811 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2812 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002813 {
2814 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002815 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002816 }
Richard Henderson084d0492013-02-10 10:30:44 -08002817
Riku Voipio1d8b5122014-04-23 10:26:05 +03002818 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002819
2820 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002821 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002822 }
bellard106ec872006-06-27 21:08:10 +00002823}
2824
Riku Voipio016d2e12014-04-23 11:19:48 +03002825static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002826restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002827{
Richard Henderson084d0492013-02-10 10:30:44 -08002828 int i;
bellard106ec872006-06-27 21:08:10 +00002829
Riku Voipio1d8b5122014-04-23 10:26:05 +03002830 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002831
Riku Voipio1d8b5122014-04-23 10:26:05 +03002832 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2833 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002834
Richard Henderson084d0492013-02-10 10:30:44 -08002835 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002836 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002837 }
2838
Riku Voipio1d8b5122014-04-23 10:26:05 +03002839 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2840 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2841 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2842 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2843 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2844 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002845 {
2846 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002847 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002848 cpu_wrdsp(dsp, 0x3ff, regs);
2849 }
2850
2851 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002852 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002853 }
bellard106ec872006-06-27 21:08:10 +00002854}
Richard Hendersonff970902013-02-10 10:30:42 -08002855
bellard106ec872006-06-27 21:08:10 +00002856/*
2857 * Determine which stack to use..
2858 */
bellard579a97f2007-11-11 14:26:47 +00002859static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002860get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002861{
2862 unsigned long sp;
2863
2864 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002865 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002866
2867 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002868 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002869 * above the user stack, 16-bytes before the next lowest
2870 * 16 byte boundary. Try to avoid trashing it.
2871 */
2872 sp -= 32;
2873
bellard106ec872006-06-27 21:08:10 +00002874 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002875 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002876 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2877 }
bellard106ec872006-06-27 21:08:10 +00002878
bellard579a97f2007-11-11 14:26:47 +00002879 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002880}
2881
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002882static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2883{
2884 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2885 env->hflags &= ~MIPS_HFLAG_M16;
2886 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2887 env->active_tc.PC &= ~(target_ulong) 1;
2888 }
2889}
2890
Richard Hendersonff970902013-02-10 10:30:42 -08002891# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002892/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002893static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002894 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002895{
2896 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002897 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002898 int i;
2899
bellard579a97f2007-11-11 14:26:47 +00002900 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002901 trace_user_setup_frame(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00002902 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002903 goto give_sigsegv;
2904
2905 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2906
Riku Voipio41ecc722014-04-23 11:01:00 +03002907 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002908
2909 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03002910 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00002911 }
2912
2913 /*
2914 * Arguments to signal handler:
2915 *
2916 * a0 = signal number
2917 * a1 = 0 (should be cause)
2918 * a2 = pointer to struct sigcontext
2919 *
2920 * $25 and PC point to the signal handler, $29 points to the
2921 * struct sigframe.
2922 */
thsb5dc7732008-06-27 10:02:35 +00002923 regs->active_tc.gpr[ 4] = sig;
2924 regs->active_tc.gpr[ 5] = 0;
2925 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2926 regs->active_tc.gpr[29] = frame_addr;
2927 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002928 /* The original kernel code sets CP0_EPC to the handler
2929 * since it returns to userland using eret
2930 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002931 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002932 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002933 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002934 return;
2935
2936give_sigsegv:
2937 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002938}
2939
Andreas Färber05390242012-02-25 03:37:53 +01002940long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002941{
ths388bb212007-05-13 13:58:00 +00002942 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002943 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002944 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002945 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002946 int i;
bellard106ec872006-06-27 21:08:10 +00002947
thsb5dc7732008-06-27 10:02:35 +00002948 frame_addr = regs->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002949 trace_user_do_sigreturn(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00002950 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002951 goto badframe;
2952
ths388bb212007-05-13 13:58:00 +00002953 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03002954 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00002955 }
bellard106ec872006-06-27 21:08:10 +00002956
ths388bb212007-05-13 13:58:00 +00002957 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002958 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002959
Riku Voipio016d2e12014-04-23 11:19:48 +03002960 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002961
2962#if 0
ths388bb212007-05-13 13:58:00 +00002963 /*
2964 * Don't let your children do this ...
2965 */
2966 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002967 "move\t$29, %0\n\t"
2968 "j\tsyscall_exit"
2969 :/* no outputs */
2970 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002971 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002972#endif
ths3b46e622007-09-17 08:09:54 +00002973
thsb5dc7732008-06-27 10:02:35 +00002974 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002975 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00002976 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002977 * maybe a problem with nested signals ? */
2978 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00002979 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00002980
2981badframe:
ths388bb212007-05-13 13:58:00 +00002982 force_sig(TARGET_SIGSEGV/*, current*/);
2983 return 0;
bellard106ec872006-06-27 21:08:10 +00002984}
Richard Hendersonff970902013-02-10 10:30:42 -08002985# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002986
pbrook624f7972008-05-31 16:11:38 +00002987static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002988 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002989 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00002990{
pbrook0b1bcb02009-04-21 01:41:10 +00002991 struct target_rt_sigframe *frame;
2992 abi_ulong frame_addr;
2993 int i;
2994
2995 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002996 trace_user_setup_rt_frame(env, frame_addr);
pbrook0b1bcb02009-04-21 01:41:10 +00002997 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2998 goto give_sigsegv;
2999
3000 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3001
Peter Maydellf6c7a052015-01-08 12:19:48 +00003002 tswap_siginfo(&frame->rs_info, info);
pbrook0b1bcb02009-04-21 01:41:10 +00003003
Aurelien Jarno60e99242010-03-29 02:12:51 +02003004 __put_user(0, &frame->rs_uc.tuc_flags);
3005 __put_user(0, &frame->rs_uc.tuc_link);
3006 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3007 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003008 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003009 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003010
Aurelien Jarno60e99242010-03-29 02:12:51 +02003011 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003012
3013 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003014 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003015 }
3016
3017 /*
3018 * Arguments to signal handler:
3019 *
3020 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003021 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003022 * a2 = pointer to struct ucontext
3023 *
3024 * $25 and PC point to the signal handler, $29 points to the
3025 * struct sigframe.
3026 */
3027 env->active_tc.gpr[ 4] = sig;
3028 env->active_tc.gpr[ 5] = frame_addr
3029 + offsetof(struct target_rt_sigframe, rs_info);
3030 env->active_tc.gpr[ 6] = frame_addr
3031 + offsetof(struct target_rt_sigframe, rs_uc);
3032 env->active_tc.gpr[29] = frame_addr;
3033 env->active_tc.gpr[31] = frame_addr
3034 + offsetof(struct target_rt_sigframe, rs_code);
3035 /* The original kernel code sets CP0_EPC to the handler
3036 * since it returns to userland using eret
3037 * we cannot do this here, and we must set PC directly */
3038 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003039 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003040 unlock_user_struct(frame, frame_addr, 1);
3041 return;
3042
3043give_sigsegv:
3044 unlock_user_struct(frame, frame_addr, 1);
3045 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003046}
3047
Andreas Färber05390242012-02-25 03:37:53 +01003048long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003049{
pbrook0b1bcb02009-04-21 01:41:10 +00003050 struct target_rt_sigframe *frame;
3051 abi_ulong frame_addr;
3052 sigset_t blocked;
3053
pbrook0b1bcb02009-04-21 01:41:10 +00003054 frame_addr = env->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003055 trace_user_do_rt_sigreturn(env, frame_addr);
pbrook0b1bcb02009-04-21 01:41:10 +00003056 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3057 goto badframe;
3058
Aurelien Jarno60e99242010-03-29 02:12:51 +02003059 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003060 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003061
Riku Voipio016d2e12014-04-23 11:19:48 +03003062 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003063
3064 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003065 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003066 0, get_sp_from_cpustate(env)) == -EFAULT)
3067 goto badframe;
3068
3069 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003070 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003071 /* I am not sure this is right, but it seems to work
3072 * maybe a problem with nested signals ? */
3073 env->CP0_EPC = 0;
3074 return -TARGET_QEMU_ESIGRETURN;
3075
3076badframe:
3077 force_sig(TARGET_SIGSEGV/*, current*/);
3078 return 0;
bellard106ec872006-06-27 21:08:10 +00003079}
bellard6d5e2162004-09-30 22:04:13 +00003080
thsc3b5bc82007-12-02 06:31:25 +00003081#elif defined(TARGET_SH4)
3082
3083/*
3084 * code and data structures from linux kernel:
3085 * include/asm-sh/sigcontext.h
3086 * arch/sh/kernel/signal.c
3087 */
3088
3089struct target_sigcontext {
3090 target_ulong oldmask;
3091
3092 /* CPU registers */
3093 target_ulong sc_gregs[16];
3094 target_ulong sc_pc;
3095 target_ulong sc_pr;
3096 target_ulong sc_sr;
3097 target_ulong sc_gbr;
3098 target_ulong sc_mach;
3099 target_ulong sc_macl;
3100
3101 /* FPU registers */
3102 target_ulong sc_fpregs[16];
3103 target_ulong sc_xfpregs[16];
3104 unsigned int sc_fpscr;
3105 unsigned int sc_fpul;
3106 unsigned int sc_ownedfp;
3107};
3108
3109struct target_sigframe
3110{
3111 struct target_sigcontext sc;
3112 target_ulong extramask[TARGET_NSIG_WORDS-1];
3113 uint16_t retcode[3];
3114};
3115
3116
3117struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003118 target_ulong tuc_flags;
3119 struct target_ucontext *tuc_link;
3120 target_stack_t tuc_stack;
3121 struct target_sigcontext tuc_mcontext;
3122 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003123};
3124
3125struct target_rt_sigframe
3126{
3127 struct target_siginfo info;
3128 struct target_ucontext uc;
3129 uint16_t retcode[3];
3130};
3131
3132
3133#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3134#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3135
pbrook624f7972008-05-31 16:11:38 +00003136static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003137 unsigned long sp, size_t frame_size)
3138{
pbrook624f7972008-05-31 16:11:38 +00003139 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003140 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3141 }
3142
3143 return (sp - frame_size) & -8ul;
3144}
3145
Riku Voipio41ecc722014-04-23 11:01:00 +03003146static void setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003147 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003148{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003149 int i;
thsc3b5bc82007-12-02 06:31:25 +00003150
Riku Voipio1d8b5122014-04-23 10:26:05 +03003151#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003152 COPY(gregs[0]); COPY(gregs[1]);
3153 COPY(gregs[2]); COPY(gregs[3]);
3154 COPY(gregs[4]); COPY(gregs[5]);
3155 COPY(gregs[6]); COPY(gregs[7]);
3156 COPY(gregs[8]); COPY(gregs[9]);
3157 COPY(gregs[10]); COPY(gregs[11]);
3158 COPY(gregs[12]); COPY(gregs[13]);
3159 COPY(gregs[14]); COPY(gregs[15]);
3160 COPY(gbr); COPY(mach);
3161 COPY(macl); COPY(pr);
3162 COPY(sr); COPY(pc);
3163#undef COPY
3164
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003165 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003166 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003167 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003168 __put_user(regs->fpscr, &sc->sc_fpscr);
3169 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003170
3171 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003172 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003173}
3174
Riku Voipio016d2e12014-04-23 11:19:48 +03003175static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003176 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003177{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003178 int i;
thsc3b5bc82007-12-02 06:31:25 +00003179
Riku Voipio1d8b5122014-04-23 10:26:05 +03003180#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003181 COPY(gregs[1]);
3182 COPY(gregs[2]); COPY(gregs[3]);
3183 COPY(gregs[4]); COPY(gregs[5]);
3184 COPY(gregs[6]); COPY(gregs[7]);
3185 COPY(gregs[8]); COPY(gregs[9]);
3186 COPY(gregs[10]); COPY(gregs[11]);
3187 COPY(gregs[12]); COPY(gregs[13]);
3188 COPY(gregs[14]); COPY(gregs[15]);
3189 COPY(gbr); COPY(mach);
3190 COPY(macl); COPY(pr);
3191 COPY(sr); COPY(pc);
3192#undef COPY
3193
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003194 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003195 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003196 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003197 __get_user(regs->fpscr, &sc->sc_fpscr);
3198 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003199
3200 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003201 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003202}
3203
pbrook624f7972008-05-31 16:11:38 +00003204static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003205 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003206{
3207 struct target_sigframe *frame;
3208 abi_ulong frame_addr;
3209 int i;
thsc3b5bc82007-12-02 06:31:25 +00003210
3211 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003212 trace_user_setup_frame(regs, frame_addr);
thsc3b5bc82007-12-02 06:31:25 +00003213 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3214 goto give_sigsegv;
3215
Riku Voipio41ecc722014-04-23 11:01:00 +03003216 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003217
3218 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003219 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003220 }
3221
3222 /* Set up to return from userspace. If provided, use a stub
3223 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003224 if (ka->sa_flags & TARGET_SA_RESTORER) {
3225 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003226 } else {
3227 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003228 abi_ulong retcode_addr = frame_addr +
3229 offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003230 __put_user(MOVW(2), &frame->retcode[0]);
3231 __put_user(TRAP_NOARG, &frame->retcode[1]);
3232 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003233 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003234 }
3235
thsc3b5bc82007-12-02 06:31:25 +00003236 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003237 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003238 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003239 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003240 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003241 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003242
3243 unlock_user_struct(frame, frame_addr, 1);
3244 return;
3245
3246give_sigsegv:
3247 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003248 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003249}
3250
pbrook624f7972008-05-31 16:11:38 +00003251static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003252 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003253 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003254{
3255 struct target_rt_sigframe *frame;
3256 abi_ulong frame_addr;
3257 int i;
thsc3b5bc82007-12-02 06:31:25 +00003258
3259 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003260 trace_user_setup_rt_frame(regs, frame_addr);
thsc3b5bc82007-12-02 06:31:25 +00003261 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3262 goto give_sigsegv;
3263
Peter Maydellf6c7a052015-01-08 12:19:48 +00003264 tswap_siginfo(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003265
3266 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003267 __put_user(0, &frame->uc.tuc_flags);
3268 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3269 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3270 &frame->uc.tuc_stack.ss_sp);
3271 __put_user(sas_ss_flags(regs->gregs[15]),
3272 &frame->uc.tuc_stack.ss_flags);
3273 __put_user(target_sigaltstack_used.ss_size,
3274 &frame->uc.tuc_stack.ss_size);
3275 setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003276 regs, set->sig[0]);
3277 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003278 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003279 }
3280
3281 /* Set up to return from userspace. If provided, use a stub
3282 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003283 if (ka->sa_flags & TARGET_SA_RESTORER) {
3284 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003285 } else {
3286 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003287 abi_ulong retcode_addr = frame_addr +
3288 offsetof(struct target_rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003289 __put_user(MOVW(2), &frame->retcode[0]);
3290 __put_user(TRAP_NOARG, &frame->retcode[1]);
3291 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003292 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003293 }
3294
thsc3b5bc82007-12-02 06:31:25 +00003295 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003296 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003297 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003298 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3299 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003300 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003301
3302 unlock_user_struct(frame, frame_addr, 1);
3303 return;
3304
3305give_sigsegv:
3306 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003307 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003308}
3309
Andreas Färber05390242012-02-25 03:37:53 +01003310long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003311{
3312 struct target_sigframe *frame;
3313 abi_ulong frame_addr;
3314 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003315 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003316 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003317 int i;
3318 int err = 0;
3319
thsc3b5bc82007-12-02 06:31:25 +00003320 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003321 trace_user_do_sigreturn(regs, frame_addr);
thsc3b5bc82007-12-02 06:31:25 +00003322 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3323 goto badframe;
3324
Riku Voipio1d8b5122014-04-23 10:26:05 +03003325 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003326 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003327 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003328 }
3329
3330 if (err)
3331 goto badframe;
3332
3333 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003334 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003335
Riku Voipio016d2e12014-04-23 11:19:48 +03003336 restore_sigcontext(regs, &frame->sc, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003337
3338 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003339 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003340
3341badframe:
3342 unlock_user_struct(frame, frame_addr, 0);
3343 force_sig(TARGET_SIGSEGV);
3344 return 0;
3345}
3346
Andreas Färber05390242012-02-25 03:37:53 +01003347long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003348{
3349 struct target_rt_sigframe *frame;
3350 abi_ulong frame_addr;
3351 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003352 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003353
thsc3b5bc82007-12-02 06:31:25 +00003354 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003355 trace_user_do_rt_sigreturn(regs, frame_addr);
thsc3b5bc82007-12-02 06:31:25 +00003356 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3357 goto badframe;
3358
Aurelien Jarno60e99242010-03-29 02:12:51 +02003359 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003360 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003361
Riku Voipio016d2e12014-04-23 11:19:48 +03003362 restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003363
3364 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003365 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003366 0, get_sp_from_cpustate(regs)) == -EFAULT)
3367 goto badframe;
3368
3369 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003370 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003371
3372badframe:
3373 unlock_user_struct(frame, frame_addr, 0);
3374 force_sig(TARGET_SIGSEGV);
3375 return 0;
3376}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003377#elif defined(TARGET_MICROBLAZE)
3378
3379struct target_sigcontext {
3380 struct target_pt_regs regs; /* needs to be first */
3381 uint32_t oldmask;
3382};
3383
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003384struct target_stack_t {
3385 abi_ulong ss_sp;
3386 int ss_flags;
3387 unsigned int ss_size;
3388};
3389
3390struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003391 abi_ulong tuc_flags;
3392 abi_ulong tuc_link;
3393 struct target_stack_t tuc_stack;
3394 struct target_sigcontext tuc_mcontext;
3395 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003396};
3397
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003398/* Signal frames. */
3399struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003400 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003401 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3402 uint32_t tramp[2];
3403};
3404
3405struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003406 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003407 struct ucontext uc;
3408 uint32_t tramp[2];
3409};
3410
Andreas Färber05390242012-02-25 03:37:53 +01003411static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003412{
3413 __put_user(env->regs[0], &sc->regs.r0);
3414 __put_user(env->regs[1], &sc->regs.r1);
3415 __put_user(env->regs[2], &sc->regs.r2);
3416 __put_user(env->regs[3], &sc->regs.r3);
3417 __put_user(env->regs[4], &sc->regs.r4);
3418 __put_user(env->regs[5], &sc->regs.r5);
3419 __put_user(env->regs[6], &sc->regs.r6);
3420 __put_user(env->regs[7], &sc->regs.r7);
3421 __put_user(env->regs[8], &sc->regs.r8);
3422 __put_user(env->regs[9], &sc->regs.r9);
3423 __put_user(env->regs[10], &sc->regs.r10);
3424 __put_user(env->regs[11], &sc->regs.r11);
3425 __put_user(env->regs[12], &sc->regs.r12);
3426 __put_user(env->regs[13], &sc->regs.r13);
3427 __put_user(env->regs[14], &sc->regs.r14);
3428 __put_user(env->regs[15], &sc->regs.r15);
3429 __put_user(env->regs[16], &sc->regs.r16);
3430 __put_user(env->regs[17], &sc->regs.r17);
3431 __put_user(env->regs[18], &sc->regs.r18);
3432 __put_user(env->regs[19], &sc->regs.r19);
3433 __put_user(env->regs[20], &sc->regs.r20);
3434 __put_user(env->regs[21], &sc->regs.r21);
3435 __put_user(env->regs[22], &sc->regs.r22);
3436 __put_user(env->regs[23], &sc->regs.r23);
3437 __put_user(env->regs[24], &sc->regs.r24);
3438 __put_user(env->regs[25], &sc->regs.r25);
3439 __put_user(env->regs[26], &sc->regs.r26);
3440 __put_user(env->regs[27], &sc->regs.r27);
3441 __put_user(env->regs[28], &sc->regs.r28);
3442 __put_user(env->regs[29], &sc->regs.r29);
3443 __put_user(env->regs[30], &sc->regs.r30);
3444 __put_user(env->regs[31], &sc->regs.r31);
3445 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3446}
3447
Andreas Färber05390242012-02-25 03:37:53 +01003448static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003449{
3450 __get_user(env->regs[0], &sc->regs.r0);
3451 __get_user(env->regs[1], &sc->regs.r1);
3452 __get_user(env->regs[2], &sc->regs.r2);
3453 __get_user(env->regs[3], &sc->regs.r3);
3454 __get_user(env->regs[4], &sc->regs.r4);
3455 __get_user(env->regs[5], &sc->regs.r5);
3456 __get_user(env->regs[6], &sc->regs.r6);
3457 __get_user(env->regs[7], &sc->regs.r7);
3458 __get_user(env->regs[8], &sc->regs.r8);
3459 __get_user(env->regs[9], &sc->regs.r9);
3460 __get_user(env->regs[10], &sc->regs.r10);
3461 __get_user(env->regs[11], &sc->regs.r11);
3462 __get_user(env->regs[12], &sc->regs.r12);
3463 __get_user(env->regs[13], &sc->regs.r13);
3464 __get_user(env->regs[14], &sc->regs.r14);
3465 __get_user(env->regs[15], &sc->regs.r15);
3466 __get_user(env->regs[16], &sc->regs.r16);
3467 __get_user(env->regs[17], &sc->regs.r17);
3468 __get_user(env->regs[18], &sc->regs.r18);
3469 __get_user(env->regs[19], &sc->regs.r19);
3470 __get_user(env->regs[20], &sc->regs.r20);
3471 __get_user(env->regs[21], &sc->regs.r21);
3472 __get_user(env->regs[22], &sc->regs.r22);
3473 __get_user(env->regs[23], &sc->regs.r23);
3474 __get_user(env->regs[24], &sc->regs.r24);
3475 __get_user(env->regs[25], &sc->regs.r25);
3476 __get_user(env->regs[26], &sc->regs.r26);
3477 __get_user(env->regs[27], &sc->regs.r27);
3478 __get_user(env->regs[28], &sc->regs.r28);
3479 __get_user(env->regs[29], &sc->regs.r29);
3480 __get_user(env->regs[30], &sc->regs.r30);
3481 __get_user(env->regs[31], &sc->regs.r31);
3482 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3483}
3484
3485static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003486 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003487{
3488 abi_ulong sp = env->regs[1];
3489
Riku Voipiob545f632014-07-15 17:01:55 +03003490 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003491 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003492 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003493
3494 return ((sp - frame_size) & -8UL);
3495}
3496
3497static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003498 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003499{
3500 struct target_signal_frame *frame;
3501 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003502 int i;
3503
3504 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003505 trace_user_setup_frame(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003506 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3507 goto badframe;
3508
3509 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003510 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003511
3512 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003513 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003514 }
3515
Richard Hendersonf711df62010-11-22 14:57:52 -08003516 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003517
3518 /* Set up to return from userspace. If provided, use a stub
3519 already in userspace. */
3520 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3521 if (ka->sa_flags & TARGET_SA_RESTORER) {
3522 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3523 } else {
3524 uint32_t t;
3525 /* Note, these encodings are _big endian_! */
3526 /* addi r12, r0, __NR_sigreturn */
3527 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003528 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003529 /* brki r14, 0x8 */
3530 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003531 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003532
3533 /* Return from sighandler will jump to the tramp.
3534 Negative 8 offset because return is rtsd r15, 8 */
3535 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3536 }
3537
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003538 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003539 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003540 /* Signal handler args: */
3541 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003542 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003543 /* arg 1: sigcontext */
3544 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003545
3546 /* Offset of 4 to handle microblaze rtid r14, 0 */
3547 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3548
3549 unlock_user_struct(frame, frame_addr, 1);
3550 return;
3551 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003552 force_sig(TARGET_SIGSEGV);
3553}
3554
3555static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003556 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003557 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003558{
3559 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3560}
3561
Andreas Färber05390242012-02-25 03:37:53 +01003562long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003563{
3564 struct target_signal_frame *frame;
3565 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003566 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003567 sigset_t set;
3568 int i;
3569
3570 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003571 trace_user_do_sigreturn(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003572 /* Make sure the guest isn't playing games. */
3573 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3574 goto badframe;
3575
3576 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003577 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003578 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003579 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003580 }
3581 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003582 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003583
Richard Hendersonf711df62010-11-22 14:57:52 -08003584 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003585 /* We got here through a sigreturn syscall, our path back is via an
3586 rtb insn so setup r14 for that. */
3587 env->regs[14] = env->sregs[SR_PC];
3588
3589 unlock_user_struct(frame, frame_addr, 0);
3590 return env->regs[10];
3591 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003592 force_sig(TARGET_SIGSEGV);
3593}
3594
Andreas Färber05390242012-02-25 03:37:53 +01003595long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003596{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003597 trace_user_do_rt_sigreturn(env, 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003598 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3599 return -TARGET_ENOSYS;
3600}
3601
edgar_iglb6d3abd2008-02-28 11:29:27 +00003602#elif defined(TARGET_CRIS)
3603
3604struct target_sigcontext {
3605 struct target_pt_regs regs; /* needs to be first */
3606 uint32_t oldmask;
3607 uint32_t usp; /* usp before stacking this gunk on it */
3608};
3609
3610/* Signal frames. */
3611struct target_signal_frame {
3612 struct target_sigcontext sc;
3613 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003614 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003615};
3616
3617struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003618 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003619 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003620 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003621 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003622 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003623};
3624
Andreas Färber05390242012-02-25 03:37:53 +01003625static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003626{
edgar_igl9664d922008-03-03 22:23:53 +00003627 __put_user(env->regs[0], &sc->regs.r0);
3628 __put_user(env->regs[1], &sc->regs.r1);
3629 __put_user(env->regs[2], &sc->regs.r2);
3630 __put_user(env->regs[3], &sc->regs.r3);
3631 __put_user(env->regs[4], &sc->regs.r4);
3632 __put_user(env->regs[5], &sc->regs.r5);
3633 __put_user(env->regs[6], &sc->regs.r6);
3634 __put_user(env->regs[7], &sc->regs.r7);
3635 __put_user(env->regs[8], &sc->regs.r8);
3636 __put_user(env->regs[9], &sc->regs.r9);
3637 __put_user(env->regs[10], &sc->regs.r10);
3638 __put_user(env->regs[11], &sc->regs.r11);
3639 __put_user(env->regs[12], &sc->regs.r12);
3640 __put_user(env->regs[13], &sc->regs.r13);
3641 __put_user(env->regs[14], &sc->usp);
3642 __put_user(env->regs[15], &sc->regs.acr);
3643 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3644 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3645 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003646}
edgar_igl9664d922008-03-03 22:23:53 +00003647
Andreas Färber05390242012-02-25 03:37:53 +01003648static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003649{
edgar_igl9664d922008-03-03 22:23:53 +00003650 __get_user(env->regs[0], &sc->regs.r0);
3651 __get_user(env->regs[1], &sc->regs.r1);
3652 __get_user(env->regs[2], &sc->regs.r2);
3653 __get_user(env->regs[3], &sc->regs.r3);
3654 __get_user(env->regs[4], &sc->regs.r4);
3655 __get_user(env->regs[5], &sc->regs.r5);
3656 __get_user(env->regs[6], &sc->regs.r6);
3657 __get_user(env->regs[7], &sc->regs.r7);
3658 __get_user(env->regs[8], &sc->regs.r8);
3659 __get_user(env->regs[9], &sc->regs.r9);
3660 __get_user(env->regs[10], &sc->regs.r10);
3661 __get_user(env->regs[11], &sc->regs.r11);
3662 __get_user(env->regs[12], &sc->regs.r12);
3663 __get_user(env->regs[13], &sc->regs.r13);
3664 __get_user(env->regs[14], &sc->usp);
3665 __get_user(env->regs[15], &sc->regs.acr);
3666 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3667 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3668 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003669}
3670
Andreas Färber05390242012-02-25 03:37:53 +01003671static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003672{
edgar_igl9664d922008-03-03 22:23:53 +00003673 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003674 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003675 sp = (env->regs[R_SP] & ~3);
3676 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003677}
3678
pbrook624f7972008-05-31 16:11:38 +00003679static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003680 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003681{
3682 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003683 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003684 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003685
edgar_igl9664d922008-03-03 22:23:53 +00003686 frame_addr = get_sigframe(env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003687 trace_user_setup_frame(env, frame_addr);
edgar_igl9664d922008-03-03 22:23:53 +00003688 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003689 goto badframe;
3690
3691 /*
3692 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3693 * use this trampoline anymore but it sets it up for GDB.
3694 * In QEMU, using the trampoline simplifies things a bit so we use it.
3695 *
3696 * This is movu.w __NR_sigreturn, r9; break 13;
3697 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003698 __put_user(0x9c5f, frame->retcode+0);
3699 __put_user(TARGET_NR_sigreturn,
3700 frame->retcode + 1);
3701 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003702
3703 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003704 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003705
Riku Voipio0188fad2014-04-23 13:34:15 +03003706 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3707 __put_user(set->sig[i], &frame->extramask[i - 1]);
3708 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003709
3710 setup_sigcontext(&frame->sc, env);
3711
3712 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003713 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003714 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003715 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003716 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003717 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003718
edgar_igl9664d922008-03-03 22:23:53 +00003719 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003720 return;
3721 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003722 force_sig(TARGET_SIGSEGV);
3723}
3724
pbrook624f7972008-05-31 16:11:38 +00003725static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003726 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003727 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003728{
3729 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3730}
3731
Andreas Färber05390242012-02-25 03:37:53 +01003732long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003733{
3734 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003735 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003736 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003737 sigset_t set;
3738 int i;
3739
edgar_igl9664d922008-03-03 22:23:53 +00003740 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003741 trace_user_do_sigreturn(env, frame_addr);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003742 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003743 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003744 goto badframe;
3745
3746 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003747 __get_user(target_set.sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003748 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003749 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003750 }
3751 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003752 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003753
3754 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003755 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003756 return env->regs[10];
3757 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003758 force_sig(TARGET_SIGSEGV);
3759}
3760
Andreas Färber05390242012-02-25 03:37:53 +01003761long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003762{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003763 trace_user_do_rt_sigreturn(env, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003764 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3765 return -TARGET_ENOSYS;
3766}
thsc3b5bc82007-12-02 06:31:25 +00003767
Jia Liud9627832012-07-20 15:50:52 +08003768#elif defined(TARGET_OPENRISC)
3769
3770struct target_sigcontext {
3771 struct target_pt_regs regs;
3772 abi_ulong oldmask;
3773 abi_ulong usp;
3774};
3775
3776struct target_ucontext {
3777 abi_ulong tuc_flags;
3778 abi_ulong tuc_link;
3779 target_stack_t tuc_stack;
3780 struct target_sigcontext tuc_mcontext;
3781 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3782};
3783
3784struct target_rt_sigframe {
3785 abi_ulong pinfo;
3786 uint64_t puc;
3787 struct target_siginfo info;
3788 struct target_sigcontext sc;
3789 struct target_ucontext uc;
3790 unsigned char retcode[16]; /* trampoline code */
3791};
3792
3793/* This is the asm-generic/ucontext.h version */
3794#if 0
3795static int restore_sigcontext(CPUOpenRISCState *regs,
3796 struct target_sigcontext *sc)
3797{
3798 unsigned int err = 0;
3799 unsigned long old_usp;
3800
3801 /* Alwys make any pending restarted system call return -EINTR */
3802 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3803
3804 /* restore the regs from &sc->regs (same as sc, since regs is first)
3805 * (sc is already checked for VERIFY_READ since the sigframe was
3806 * checked in sys_sigreturn previously)
3807 */
3808
3809 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3810 goto badframe;
3811 }
3812
3813 /* make sure the U-flag is set so user-mode cannot fool us */
3814
3815 regs->sr &= ~SR_SM;
3816
3817 /* restore the old USP as it was before we stacked the sc etc.
3818 * (we cannot just pop the sigcontext since we aligned the sp and
3819 * stuff after pushing it)
3820 */
3821
Riku Voipio1d8b5122014-04-23 10:26:05 +03003822 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003823 phx_signal("old_usp 0x%lx", old_usp);
3824
3825 __PHX__ REALLY /* ??? */
3826 wrusp(old_usp);
3827 regs->gpr[1] = old_usp;
3828
3829 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3830 * after this completes, but we don't use that mechanism. maybe we can
3831 * use it now ?
3832 */
3833
3834 return err;
3835
3836badframe:
3837 return 1;
3838}
3839#endif
3840
3841/* Set up a signal frame. */
3842
Riku Voipio41ecc722014-04-23 11:01:00 +03003843static void setup_sigcontext(struct target_sigcontext *sc,
Jia Liud9627832012-07-20 15:50:52 +08003844 CPUOpenRISCState *regs,
3845 unsigned long mask)
3846{
Jia Liud9627832012-07-20 15:50:52 +08003847 unsigned long usp = regs->gpr[1];
3848
3849 /* copy the regs. they are first in sc so we can use sc directly */
3850
Riku Voipio1d8b5122014-04-23 10:26:05 +03003851 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003852
3853 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3854 the signal handler. The frametype will be restored to its previous
3855 value in restore_sigcontext. */
3856 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3857
3858 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003859 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003860 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003861}
3862
3863static inline unsigned long align_sigframe(unsigned long sp)
3864{
3865 unsigned long i;
3866 i = sp & ~3UL;
3867 return i;
3868}
3869
3870static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3871 CPUOpenRISCState *regs,
3872 size_t frame_size)
3873{
3874 unsigned long sp = regs->gpr[1];
3875 int onsigstack = on_sig_stack(sp);
3876
3877 /* redzone */
3878 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03003879 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08003880 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3881 }
3882
3883 sp = align_sigframe(sp - frame_size);
3884
3885 /*
3886 * If we are on the alternate signal stack and would overflow it, don't.
3887 * Return an always-bogus address instead so we will die with SIGSEGV.
3888 */
3889
3890 if (onsigstack && !likely(on_sig_stack(sp))) {
3891 return -1L;
3892 }
3893
3894 return sp;
3895}
3896
Jia Liud9627832012-07-20 15:50:52 +08003897static void setup_rt_frame(int sig, struct target_sigaction *ka,
3898 target_siginfo_t *info,
3899 target_sigset_t *set, CPUOpenRISCState *env)
3900{
3901 int err = 0;
3902 abi_ulong frame_addr;
3903 unsigned long return_ip;
3904 struct target_rt_sigframe *frame;
3905 abi_ulong info_addr, uc_addr;
3906
Jia Liud9627832012-07-20 15:50:52 +08003907 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003908 trace_user_setup_rt_frame(env, frame_addr);
Jia Liud9627832012-07-20 15:50:52 +08003909 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3910 goto give_sigsegv;
3911 }
3912
3913 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003914 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08003915 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003916 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08003917
3918 if (ka->sa_flags & SA_SIGINFO) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00003919 tswap_siginfo(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08003920 }
3921
3922 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03003923 __put_user(0, &frame->uc.tuc_flags);
3924 __put_user(0, &frame->uc.tuc_link);
3925 __put_user(target_sigaltstack_used.ss_sp,
3926 &frame->uc.tuc_stack.ss_sp);
3927 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3928 __put_user(target_sigaltstack_used.ss_size,
3929 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03003930 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08003931
3932 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3933
Jia Liud9627832012-07-20 15:50:52 +08003934 /* trampoline - the desired return ip is the retcode itself */
3935 return_ip = (unsigned long)&frame->retcode;
3936 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003937 __put_user(0xa960, (short *)(frame->retcode + 0));
3938 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
3939 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
3940 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08003941
3942 if (err) {
3943 goto give_sigsegv;
3944 }
3945
3946 /* TODO what is the current->exec_domain stuff and invmap ? */
3947
3948 /* Set up registers for signal handler */
3949 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
3950 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
3951 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
3952 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
3953 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
3954
3955 /* actually move the usp to reflect the stacked frame */
3956 env->gpr[1] = (unsigned long)frame;
3957
3958 return;
3959
3960give_sigsegv:
3961 unlock_user_struct(frame, frame_addr, 1);
3962 if (sig == TARGET_SIGSEGV) {
3963 ka->_sa_handler = TARGET_SIG_DFL;
3964 }
3965 force_sig(TARGET_SIGSEGV);
3966}
3967
3968long do_sigreturn(CPUOpenRISCState *env)
3969{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003970 trace_user_do_sigreturn(env, 0);
3971 fprintf(stderr, "do_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08003972 return -TARGET_ENOSYS;
3973}
3974
3975long do_rt_sigreturn(CPUOpenRISCState *env)
3976{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003977 trace_user_do_rt_sigreturn(env, 0);
3978 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08003979 return -TARGET_ENOSYS;
3980}
3981/* TARGET_OPENRISC */
3982
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003983#elif defined(TARGET_S390X)
3984
3985#define __NUM_GPRS 16
3986#define __NUM_FPRS 16
3987#define __NUM_ACRS 16
3988
3989#define S390_SYSCALL_SIZE 2
3990#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
3991
3992#define _SIGCONTEXT_NSIG 64
3993#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
3994#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
3995#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
3996#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
3997#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
3998
3999typedef struct {
4000 target_psw_t psw;
4001 target_ulong gprs[__NUM_GPRS];
4002 unsigned int acrs[__NUM_ACRS];
4003} target_s390_regs_common;
4004
4005typedef struct {
4006 unsigned int fpc;
4007 double fprs[__NUM_FPRS];
4008} target_s390_fp_regs;
4009
4010typedef struct {
4011 target_s390_regs_common regs;
4012 target_s390_fp_regs fpregs;
4013} target_sigregs;
4014
4015struct target_sigcontext {
4016 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4017 target_sigregs *sregs;
4018};
4019
4020typedef struct {
4021 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4022 struct target_sigcontext sc;
4023 target_sigregs sregs;
4024 int signo;
4025 uint8_t retcode[S390_SYSCALL_SIZE];
4026} sigframe;
4027
4028struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004029 target_ulong tuc_flags;
4030 struct target_ucontext *tuc_link;
4031 target_stack_t tuc_stack;
4032 target_sigregs tuc_mcontext;
4033 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004034};
4035
4036typedef struct {
4037 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4038 uint8_t retcode[S390_SYSCALL_SIZE];
4039 struct target_siginfo info;
4040 struct target_ucontext uc;
4041} rt_sigframe;
4042
4043static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004044get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004045{
4046 abi_ulong sp;
4047
4048 /* Default to using normal stack */
4049 sp = env->regs[15];
4050
4051 /* This is the X/Open sanctioned signal stack switching. */
4052 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4053 if (!sas_ss_flags(sp)) {
4054 sp = target_sigaltstack_used.ss_sp +
4055 target_sigaltstack_used.ss_size;
4056 }
4057 }
4058
4059 /* This is the legacy signal stack switching. */
4060 else if (/* FIXME !user_mode(regs) */ 0 &&
4061 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4062 ka->sa_restorer) {
4063 sp = (abi_ulong) ka->sa_restorer;
4064 }
4065
4066 return (sp - frame_size) & -8ul;
4067}
4068
Andreas Färber05390242012-02-25 03:37:53 +01004069static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004070{
4071 int i;
4072 //save_access_regs(current->thread.acrs); FIXME
4073
4074 /* Copy a 'clean' PSW mask to the user to avoid leaking
4075 information about whether PER is currently on. */
4076 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4077 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4078 for (i = 0; i < 16; i++) {
4079 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4080 }
4081 for (i = 0; i < 16; i++) {
4082 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4083 }
4084 /*
4085 * We have to store the fp registers to current->thread.fp_regs
4086 * to merge them with the emulated registers.
4087 */
4088 //save_fp_regs(&current->thread.fp_regs); FIXME
4089 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004090 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004091 }
4092}
4093
4094static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004095 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004096{
4097 sigframe *frame;
4098 abi_ulong frame_addr;
4099
4100 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004101 trace_user_setup_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004102 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4103 goto give_sigsegv;
4104 }
4105
Riku Voipio0188fad2014-04-23 13:34:15 +03004106 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004107
4108 save_sigregs(env, &frame->sregs);
4109
4110 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4111 (abi_ulong *)&frame->sc.sregs);
4112
4113 /* Set up to return from userspace. If provided, use a stub
4114 already in userspace. */
4115 if (ka->sa_flags & TARGET_SA_RESTORER) {
4116 env->regs[14] = (unsigned long)
4117 ka->sa_restorer | PSW_ADDR_AMODE;
4118 } else {
4119 env->regs[14] = (unsigned long)
4120 frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004121 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4122 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004123 }
4124
4125 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004126 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004127
4128 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004129 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004130 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4131
4132 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004133 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004134
4135 /* We forgot to include these in the sigcontext.
4136 To avoid breaking binary compatibility, they are passed as args. */
4137 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4138 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4139
4140 /* Place signal number on stack to allow backtrace from handler. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004141 __put_user(env->regs[2], (int *) &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004142 unlock_user_struct(frame, frame_addr, 1);
4143 return;
4144
4145give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004146 force_sig(TARGET_SIGSEGV);
4147}
4148
4149static void setup_rt_frame(int sig, struct target_sigaction *ka,
4150 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004151 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004152{
4153 int i;
4154 rt_sigframe *frame;
4155 abi_ulong frame_addr;
4156
4157 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004158 trace_user_setup_rt_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004159 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4160 goto give_sigsegv;
4161 }
4162
Peter Maydellf6c7a052015-01-08 12:19:48 +00004163 tswap_siginfo(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004164
4165 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004166 __put_user(0, &frame->uc.tuc_flags);
4167 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4168 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004169 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004170 &frame->uc.tuc_stack.ss_flags);
4171 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4172 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004173 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4174 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004175 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004176 }
4177
4178 /* Set up to return from userspace. If provided, use a stub
4179 already in userspace. */
4180 if (ka->sa_flags & TARGET_SA_RESTORER) {
4181 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4182 } else {
4183 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004184 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4185 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004186 }
4187
4188 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004189 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004190
4191 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004192 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004193 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4194
4195 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004196 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4197 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004198 return;
4199
4200give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004201 force_sig(TARGET_SIGSEGV);
4202}
4203
4204static int
Andreas Färber05390242012-02-25 03:37:53 +01004205restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004206{
4207 int err = 0;
4208 int i;
4209
4210 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004211 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004212 }
4213
Riku Voipio1d8b5122014-04-23 10:26:05 +03004214 __get_user(env->psw.mask, &sc->regs.psw.mask);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004215 trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
4216 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004217 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004218 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4219
4220 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004221 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004222 }
4223 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004224 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004225 }
4226
4227 return err;
4228}
4229
Andreas Färber05390242012-02-25 03:37:53 +01004230long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004231{
4232 sigframe *frame;
4233 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004234 target_sigset_t target_set;
4235 sigset_t set;
4236
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004237 trace_user_do_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004238 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4239 goto badframe;
4240 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004241 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004242
4243 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004244 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004245
4246 if (restore_sigregs(env, &frame->sregs)) {
4247 goto badframe;
4248 }
4249
4250 unlock_user_struct(frame, frame_addr, 0);
4251 return env->regs[2];
4252
4253badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004254 force_sig(TARGET_SIGSEGV);
4255 return 0;
4256}
4257
Andreas Färber05390242012-02-25 03:37:53 +01004258long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004259{
4260 rt_sigframe *frame;
4261 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004262 sigset_t set;
4263
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004264 trace_user_do_rt_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004265 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4266 goto badframe;
4267 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004268 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004269
Alex Barcelo1c275922014-03-14 14:36:55 +00004270 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004271
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004272 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004273 goto badframe;
4274 }
4275
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004276 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004277 get_sp_from_cpustate(env)) == -EFAULT) {
4278 goto badframe;
4279 }
4280 unlock_user_struct(frame, frame_addr, 0);
4281 return env->regs[2];
4282
4283badframe:
4284 unlock_user_struct(frame, frame_addr, 0);
4285 force_sig(TARGET_SIGSEGV);
4286 return 0;
4287}
4288
Tom Musta61e75fe2014-06-30 08:13:38 -05004289#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004290
4291/* Size of dummy stack frame allocated when calling signal handler.
4292 See arch/powerpc/include/asm/ptrace.h. */
4293#if defined(TARGET_PPC64)
4294#define SIGNAL_FRAMESIZE 128
4295#else
4296#define SIGNAL_FRAMESIZE 64
4297#endif
4298
Tom Musta61e75fe2014-06-30 08:13:38 -05004299/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4300 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4301struct target_mcontext {
4302 target_ulong mc_gregs[48];
4303 /* Includes fpscr. */
4304 uint64_t mc_fregs[33];
4305 target_ulong mc_pad[2];
4306 /* We need to handle Altivec and SPE at the same time, which no
4307 kernel needs to do. Fortunately, the kernel defines this bit to
4308 be Altivec-register-large all the time, rather than trying to
4309 twiddle it based on the specific platform. */
4310 union {
4311 /* SPE vector registers. One extra for SPEFSCR. */
4312 uint32_t spe[33];
4313 /* Altivec vector registers. The packing of VSCR and VRSAVE
4314 varies depending on whether we're PPC64 or not: PPC64 splits
4315 them apart; PPC32 stuffs them together. */
4316#if defined(TARGET_PPC64)
4317#define QEMU_NVRREG 34
4318#else
4319#define QEMU_NVRREG 33
4320#endif
4321 ppc_avr_t altivec[QEMU_NVRREG];
4322#undef QEMU_NVRREG
4323 } mc_vregs __attribute__((__aligned__(16)));
4324};
4325
Nathan Froydbcd49332009-05-12 19:13:18 -07004326/* See arch/powerpc/include/asm/sigcontext.h. */
4327struct target_sigcontext {
4328 target_ulong _unused[4];
4329 int32_t signal;
4330#if defined(TARGET_PPC64)
4331 int32_t pad0;
4332#endif
4333 target_ulong handler;
4334 target_ulong oldmask;
4335 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004336#if defined(TARGET_PPC64)
4337 struct target_mcontext mcontext;
4338#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004339};
4340
4341/* Indices for target_mcontext.mc_gregs, below.
4342 See arch/powerpc/include/asm/ptrace.h for details. */
4343enum {
4344 TARGET_PT_R0 = 0,
4345 TARGET_PT_R1 = 1,
4346 TARGET_PT_R2 = 2,
4347 TARGET_PT_R3 = 3,
4348 TARGET_PT_R4 = 4,
4349 TARGET_PT_R5 = 5,
4350 TARGET_PT_R6 = 6,
4351 TARGET_PT_R7 = 7,
4352 TARGET_PT_R8 = 8,
4353 TARGET_PT_R9 = 9,
4354 TARGET_PT_R10 = 10,
4355 TARGET_PT_R11 = 11,
4356 TARGET_PT_R12 = 12,
4357 TARGET_PT_R13 = 13,
4358 TARGET_PT_R14 = 14,
4359 TARGET_PT_R15 = 15,
4360 TARGET_PT_R16 = 16,
4361 TARGET_PT_R17 = 17,
4362 TARGET_PT_R18 = 18,
4363 TARGET_PT_R19 = 19,
4364 TARGET_PT_R20 = 20,
4365 TARGET_PT_R21 = 21,
4366 TARGET_PT_R22 = 22,
4367 TARGET_PT_R23 = 23,
4368 TARGET_PT_R24 = 24,
4369 TARGET_PT_R25 = 25,
4370 TARGET_PT_R26 = 26,
4371 TARGET_PT_R27 = 27,
4372 TARGET_PT_R28 = 28,
4373 TARGET_PT_R29 = 29,
4374 TARGET_PT_R30 = 30,
4375 TARGET_PT_R31 = 31,
4376 TARGET_PT_NIP = 32,
4377 TARGET_PT_MSR = 33,
4378 TARGET_PT_ORIG_R3 = 34,
4379 TARGET_PT_CTR = 35,
4380 TARGET_PT_LNK = 36,
4381 TARGET_PT_XER = 37,
4382 TARGET_PT_CCR = 38,
4383 /* Yes, there are two registers with #39. One is 64-bit only. */
4384 TARGET_PT_MQ = 39,
4385 TARGET_PT_SOFTE = 39,
4386 TARGET_PT_TRAP = 40,
4387 TARGET_PT_DAR = 41,
4388 TARGET_PT_DSISR = 42,
4389 TARGET_PT_RESULT = 43,
4390 TARGET_PT_REGS_COUNT = 44
4391};
4392
Nathan Froydbcd49332009-05-12 19:13:18 -07004393
4394struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004395 target_ulong tuc_flags;
4396 target_ulong tuc_link; /* struct ucontext __user * */
4397 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004398#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004399 int32_t tuc_pad[7];
4400 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004401 points to uc_mcontext field */
4402#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004403 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004404#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004405 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004406 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004407#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004408 int32_t tuc_maskext[30];
4409 int32_t tuc_pad2[3];
4410 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004411#endif
4412};
4413
4414/* See arch/powerpc/kernel/signal_32.c. */
4415struct target_sigframe {
4416 struct target_sigcontext sctx;
4417 struct target_mcontext mctx;
4418 int32_t abigap[56];
4419};
4420
Tom Musta61e75fe2014-06-30 08:13:38 -05004421#if defined(TARGET_PPC64)
4422
4423#define TARGET_TRAMP_SIZE 6
4424
4425struct target_rt_sigframe {
4426 /* sys_rt_sigreturn requires the ucontext be the first field */
4427 struct target_ucontext uc;
4428 target_ulong _unused[2];
4429 uint32_t trampoline[TARGET_TRAMP_SIZE];
4430 target_ulong pinfo; /* struct siginfo __user * */
4431 target_ulong puc; /* void __user * */
4432 struct target_siginfo info;
4433 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4434 char abigap[288];
4435} __attribute__((aligned(16)));
4436
4437#else
4438
Nathan Froydbcd49332009-05-12 19:13:18 -07004439struct target_rt_sigframe {
4440 struct target_siginfo info;
4441 struct target_ucontext uc;
4442 int32_t abigap[56];
4443};
4444
Tom Musta61e75fe2014-06-30 08:13:38 -05004445#endif
4446
Tom Musta8d6ab332014-06-30 08:13:39 -05004447#if defined(TARGET_PPC64)
4448
4449struct target_func_ptr {
4450 target_ulong entry;
4451 target_ulong toc;
4452};
4453
4454#endif
4455
Nathan Froydbcd49332009-05-12 19:13:18 -07004456/* We use the mc_pad field for the signal return trampoline. */
4457#define tramp mc_pad
4458
4459/* See arch/powerpc/kernel/signal.c. */
4460static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004461 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004462 int frame_size)
4463{
4464 target_ulong oldsp, newsp;
4465
4466 oldsp = env->gpr[1];
4467
4468 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004469 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004470 oldsp = (target_sigaltstack_used.ss_sp
4471 + target_sigaltstack_used.ss_size);
4472 }
4473
4474 newsp = (oldsp - frame_size) & ~0xFUL;
4475
4476 return newsp;
4477}
4478
Tom Musta76781082014-06-30 08:13:37 -05004479static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004480{
4481 target_ulong msr = env->msr;
4482 int i;
4483 target_ulong ccr = 0;
4484
4485 /* In general, the kernel attempts to be intelligent about what it
4486 needs to save for Altivec/FP/SPE registers. We don't care that
4487 much, so we just go ahead and save everything. */
4488
4489 /* Save general registers. */
4490 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004491 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004492 }
Riku Voipioc650c002014-04-23 13:53:45 +03004493 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4494 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4495 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4496 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004497
4498 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4499 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4500 }
Riku Voipioc650c002014-04-23 13:53:45 +03004501 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004502
4503 /* Save Altivec registers if necessary. */
4504 if (env->insns_flags & PPC_ALTIVEC) {
4505 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004506 ppc_avr_t *avr = &env->avr[i];
4507 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004508
Riku Voipioc650c002014-04-23 13:53:45 +03004509 __put_user(avr->u64[0], &vreg->u64[0]);
4510 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004511 }
4512 /* Set MSR_VR in the saved MSR value to indicate that
4513 frame->mc_vregs contains valid data. */
4514 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004515 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4516 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004517 }
4518
4519 /* Save floating point registers. */
4520 if (env->insns_flags & PPC_FLOAT) {
4521 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004522 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004523 }
Riku Voipioc650c002014-04-23 13:53:45 +03004524 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004525 }
4526
4527 /* Save SPE registers. The kernel only saves the high half. */
4528 if (env->insns_flags & PPC_SPE) {
4529#if defined(TARGET_PPC64)
4530 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004531 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004532 }
4533#else
4534 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004535 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004536 }
4537#endif
4538 /* Set MSR_SPE in the saved MSR value to indicate that
4539 frame->mc_vregs contains valid data. */
4540 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004541 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004542 }
4543
4544 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004545 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004546}
Nathan Froydbcd49332009-05-12 19:13:18 -07004547
Tom Musta76781082014-06-30 08:13:37 -05004548static void encode_trampoline(int sigret, uint32_t *tramp)
4549{
Nathan Froydbcd49332009-05-12 19:13:18 -07004550 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4551 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004552 __put_user(0x38000000 | sigret, &tramp[0]);
4553 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004554 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004555}
4556
Riku Voipioc650c002014-04-23 13:53:45 +03004557static void restore_user_regs(CPUPPCState *env,
4558 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004559{
4560 target_ulong save_r2 = 0;
4561 target_ulong msr;
4562 target_ulong ccr;
4563
4564 int i;
4565
4566 if (!sig) {
4567 save_r2 = env->gpr[2];
4568 }
4569
4570 /* Restore general registers. */
4571 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004572 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004573 }
Riku Voipioc650c002014-04-23 13:53:45 +03004574 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4575 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4576 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4577 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4578 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004579
4580 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4581 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4582 }
4583
4584 if (!sig) {
4585 env->gpr[2] = save_r2;
4586 }
4587 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004588 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004589
4590 /* If doing signal return, restore the previous little-endian mode. */
4591 if (sig)
4592 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4593
4594 /* Restore Altivec registers if necessary. */
4595 if (env->insns_flags & PPC_ALTIVEC) {
4596 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004597 ppc_avr_t *avr = &env->avr[i];
4598 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004599
Riku Voipioc650c002014-04-23 13:53:45 +03004600 __get_user(avr->u64[0], &vreg->u64[0]);
4601 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004602 }
4603 /* Set MSR_VEC in the saved MSR value to indicate that
4604 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004605 __get_user(env->spr[SPR_VRSAVE],
4606 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004607 }
4608
4609 /* Restore floating point registers. */
4610 if (env->insns_flags & PPC_FLOAT) {
4611 uint64_t fpscr;
4612 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004613 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004614 }
Riku Voipioc650c002014-04-23 13:53:45 +03004615 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004616 env->fpscr = (uint32_t) fpscr;
4617 }
4618
4619 /* Save SPE registers. The kernel only saves the high half. */
4620 if (env->insns_flags & PPC_SPE) {
4621#if defined(TARGET_PPC64)
4622 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4623 uint32_t hi;
4624
Riku Voipioc650c002014-04-23 13:53:45 +03004625 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004626 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4627 }
4628#else
4629 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004630 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004631 }
4632#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004633 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004634 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004635}
4636
4637static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004638 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004639{
4640 struct target_sigframe *frame;
4641 struct target_sigcontext *sc;
4642 target_ulong frame_addr, newsp;
4643 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004644#if defined(TARGET_PPC64)
4645 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4646#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004647
4648 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004649 trace_user_setup_frame(env, frame_addr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004650 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4651 goto sigsegv;
4652 sc = &frame->sctx;
4653
Riku Voipio1d8b5122014-04-23 10:26:05 +03004654 __put_user(ka->_sa_handler, &sc->handler);
4655 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004656#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004657 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004658#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004659 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004660#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004661 __put_user(h2g(&frame->mctx), &sc->regs);
4662 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004663
4664 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004665 save_user_regs(env, &frame->mctx);
4666
4667 /* Construct the trampoline code on the stack. */
4668 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004669
4670 /* The kernel checks for the presence of a VDSO here. We don't
4671 emulate a vdso, so use a sigreturn system call. */
4672 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4673
4674 /* Turn off all fp exceptions. */
4675 env->fpscr = 0;
4676
4677 /* Create a stack frame for the caller of the handler. */
4678 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004679 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004680
4681 if (err)
4682 goto sigsegv;
4683
4684 /* Set up registers for signal handler. */
4685 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004686 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004687 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004688
4689#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004690 if (get_ppc64_abi(image) < 2) {
4691 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4692 struct target_func_ptr *handler =
4693 (struct target_func_ptr *)g2h(ka->_sa_handler);
4694 env->nip = tswapl(handler->entry);
4695 env->gpr[2] = tswapl(handler->toc);
4696 } else {
4697 /* ELFv2 PPC64 function pointers are entry points, but R12
4698 * must also be set */
4699 env->nip = tswapl((target_ulong) ka->_sa_handler);
4700 env->gpr[12] = env->nip;
4701 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004702#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004703 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004704#endif
4705
Nathan Froydbcd49332009-05-12 19:13:18 -07004706 /* Signal handlers are entered in big-endian mode. */
4707 env->msr &= ~MSR_LE;
4708
4709 unlock_user_struct(frame, frame_addr, 1);
4710 return;
4711
4712sigsegv:
4713 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004714 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004715}
4716
4717static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004718 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004719 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004720{
4721 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004722 uint32_t *trampptr = 0;
4723 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004724 target_ulong rt_sf_addr, newsp = 0;
4725 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004726#if defined(TARGET_PPC64)
4727 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4728#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004729
4730 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4731 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4732 goto sigsegv;
4733
Peter Maydellf6c7a052015-01-08 12:19:48 +00004734 tswap_siginfo(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004735
Riku Voipio1d8b5122014-04-23 10:26:05 +03004736 __put_user(0, &rt_sf->uc.tuc_flags);
4737 __put_user(0, &rt_sf->uc.tuc_link);
4738 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4739 &rt_sf->uc.tuc_stack.ss_sp);
4740 __put_user(sas_ss_flags(env->gpr[1]),
4741 &rt_sf->uc.tuc_stack.ss_flags);
4742 __put_user(target_sigaltstack_used.ss_size,
4743 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004744#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004745 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4746 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004747#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004748 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004749 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004750 }
4751
Tom Musta61e75fe2014-06-30 08:13:38 -05004752#if defined(TARGET_PPC64)
4753 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4754 trampptr = &rt_sf->trampoline[0];
4755#else
4756 mctx = &rt_sf->uc.tuc_mcontext;
4757 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4758#endif
4759
4760 save_user_regs(env, mctx);
4761 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004762
4763 /* The kernel checks for the presence of a VDSO here. We don't
4764 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004765 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004766
4767 /* Turn off all fp exceptions. */
4768 env->fpscr = 0;
4769
4770 /* Create a stack frame for the caller of the handler. */
4771 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004772 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004773
4774 if (err)
4775 goto sigsegv;
4776
4777 /* Set up registers for signal handler. */
4778 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004779 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004780 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4781 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4782 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004783
4784#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004785 if (get_ppc64_abi(image) < 2) {
4786 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4787 struct target_func_ptr *handler =
4788 (struct target_func_ptr *)g2h(ka->_sa_handler);
4789 env->nip = tswapl(handler->entry);
4790 env->gpr[2] = tswapl(handler->toc);
4791 } else {
4792 /* ELFv2 PPC64 function pointers are entry points, but R12
4793 * must also be set */
4794 env->nip = tswapl((target_ulong) ka->_sa_handler);
4795 env->gpr[12] = env->nip;
4796 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004797#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004798 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004799#endif
4800
Nathan Froydbcd49332009-05-12 19:13:18 -07004801 /* Signal handlers are entered in big-endian mode. */
4802 env->msr &= ~MSR_LE;
4803
4804 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4805 return;
4806
4807sigsegv:
4808 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004809 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004810
4811}
4812
Andreas Färber05390242012-02-25 03:37:53 +01004813long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004814{
4815 struct target_sigcontext *sc = NULL;
4816 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004817 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004818 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004819 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004820
4821 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4822 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4823 goto sigsegv;
4824
4825#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004826 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004827#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004828 __get_user(set.sig[0], &sc->oldmask);
4829 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004830#endif
4831 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004832 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004833
Riku Voipiof5f601a2014-04-23 13:00:17 +03004834 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004835 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4836 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004837 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004838
4839 unlock_user_struct(sr, sr_addr, 1);
4840 unlock_user_struct(sc, sc_addr, 1);
4841 return -TARGET_QEMU_ESIGRETURN;
4842
4843sigsegv:
4844 unlock_user_struct(sr, sr_addr, 1);
4845 unlock_user_struct(sc, sc_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004846 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004847 return 0;
4848}
4849
4850/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004851static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004852{
4853 struct target_mcontext *mcp;
4854 target_ulong mcp_addr;
4855 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004856 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004857
Aurelien Jarno60e99242010-03-29 02:12:51 +02004858 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004859 sizeof (set)))
4860 return 1;
4861
Tom Musta19774ec2014-06-30 08:13:40 -05004862#if defined(TARGET_PPC64)
4863 mcp_addr = h2g(ucp) +
4864 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4865#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004866 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004867#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004868
4869 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4870 return 1;
4871
4872 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004873 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Riku Voipioc650c002014-04-23 13:53:45 +03004874 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004875
4876 unlock_user_struct(mcp, mcp_addr, 1);
4877 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004878}
4879
Andreas Färber05390242012-02-25 03:37:53 +01004880long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004881{
4882 struct target_rt_sigframe *rt_sf = NULL;
4883 target_ulong rt_sf_addr;
4884
4885 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4886 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4887 goto sigsegv;
4888
4889 if (do_setcontext(&rt_sf->uc, env, 1))
4890 goto sigsegv;
4891
4892 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004893 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004894 0, env->gpr[1]);
4895
4896 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4897 return -TARGET_QEMU_ESIGRETURN;
4898
4899sigsegv:
4900 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004901 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004902 return 0;
4903}
4904
Laurent Vivier492a8742009-08-03 16:12:17 +02004905#elif defined(TARGET_M68K)
4906
4907struct target_sigcontext {
4908 abi_ulong sc_mask;
4909 abi_ulong sc_usp;
4910 abi_ulong sc_d0;
4911 abi_ulong sc_d1;
4912 abi_ulong sc_a0;
4913 abi_ulong sc_a1;
4914 unsigned short sc_sr;
4915 abi_ulong sc_pc;
4916};
4917
4918struct target_sigframe
4919{
4920 abi_ulong pretcode;
4921 int sig;
4922 int code;
4923 abi_ulong psc;
4924 char retcode[8];
4925 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4926 struct target_sigcontext sc;
4927};
Laurent Vivier71811552009-08-03 16:12:18 +02004928
Anthony Liguoric227f092009-10-01 16:12:16 -05004929typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004930#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004931typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004932
4933typedef struct target_fpregset {
4934 int f_fpcntl[3];
4935 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05004936} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004937
4938struct target_mcontext {
4939 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05004940 target_gregset_t gregs;
4941 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004942};
4943
4944#define TARGET_MCONTEXT_VERSION 2
4945
4946struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004947 abi_ulong tuc_flags;
4948 abi_ulong tuc_link;
4949 target_stack_t tuc_stack;
4950 struct target_mcontext tuc_mcontext;
4951 abi_long tuc_filler[80];
4952 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02004953};
4954
4955struct target_rt_sigframe
4956{
4957 abi_ulong pretcode;
4958 int sig;
4959 abi_ulong pinfo;
4960 abi_ulong puc;
4961 char retcode[8];
4962 struct target_siginfo info;
4963 struct target_ucontext uc;
4964};
Laurent Vivier492a8742009-08-03 16:12:17 +02004965
Riku Voipio41ecc722014-04-23 11:01:00 +03004966static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
4967 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02004968{
Riku Voipio1d8b5122014-04-23 10:26:05 +03004969 __put_user(mask, &sc->sc_mask);
4970 __put_user(env->aregs[7], &sc->sc_usp);
4971 __put_user(env->dregs[0], &sc->sc_d0);
4972 __put_user(env->dregs[1], &sc->sc_d1);
4973 __put_user(env->aregs[0], &sc->sc_a0);
4974 __put_user(env->aregs[1], &sc->sc_a1);
4975 __put_user(env->sr, &sc->sc_sr);
4976 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02004977}
4978
Riku Voipio016d2e12014-04-23 11:19:48 +03004979static void
Andreas Färber05390242012-02-25 03:37:53 +01004980restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02004981{
Laurent Vivier492a8742009-08-03 16:12:17 +02004982 int temp;
4983
Riku Voipio1d8b5122014-04-23 10:26:05 +03004984 __get_user(env->aregs[7], &sc->sc_usp);
4985 __get_user(env->dregs[1], &sc->sc_d1);
4986 __get_user(env->aregs[0], &sc->sc_a0);
4987 __get_user(env->aregs[1], &sc->sc_a1);
4988 __get_user(env->pc, &sc->sc_pc);
4989 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02004990 env->sr = (env->sr & 0xff00) | (temp & 0xff);
4991
4992 *pd0 = tswapl(sc->sc_d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02004993}
4994
4995/*
4996 * Determine which stack to use..
4997 */
4998static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004999get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5000 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005001{
5002 unsigned long sp;
5003
5004 sp = regs->aregs[7];
5005
5006 /* This is the X/Open sanctioned signal stack switching. */
5007 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5008 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5009 }
5010
5011 return ((sp - frame_size) & -8UL);
5012}
5013
5014static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005015 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005016{
5017 struct target_sigframe *frame;
5018 abi_ulong frame_addr;
5019 abi_ulong retcode_addr;
5020 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005021 int i;
5022
5023 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005024 trace_user_setup_frame(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005025 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5026 goto give_sigsegv;
5027
Riku Voipio1d8b5122014-04-23 10:26:05 +03005028 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005029
5030 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005031 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005032
Riku Voipio41ecc722014-04-23 11:01:00 +03005033 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005034
5035 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005036 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005037 }
5038
5039 /* Set up to return from userspace. */
5040
5041 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005042 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005043
5044 /* moveq #,d0; trap #0 */
5045
Riku Voipio1d8b5122014-04-23 10:26:05 +03005046 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005047 (uint32_t *)(frame->retcode));
Laurent Vivier492a8742009-08-03 16:12:17 +02005048
Laurent Vivier492a8742009-08-03 16:12:17 +02005049 /* Set up to return from userspace */
5050
5051 env->aregs[7] = frame_addr;
5052 env->pc = ka->_sa_handler;
5053
5054 unlock_user_struct(frame, frame_addr, 1);
5055 return;
5056
5057give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005058 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005059}
5060
Laurent Vivier71811552009-08-03 16:12:18 +02005061static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005062 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005063{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005064 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005065
Riku Voipio1d8b5122014-04-23 10:26:05 +03005066 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5067 __put_user(env->dregs[0], &gregs[0]);
5068 __put_user(env->dregs[1], &gregs[1]);
5069 __put_user(env->dregs[2], &gregs[2]);
5070 __put_user(env->dregs[3], &gregs[3]);
5071 __put_user(env->dregs[4], &gregs[4]);
5072 __put_user(env->dregs[5], &gregs[5]);
5073 __put_user(env->dregs[6], &gregs[6]);
5074 __put_user(env->dregs[7], &gregs[7]);
5075 __put_user(env->aregs[0], &gregs[8]);
5076 __put_user(env->aregs[1], &gregs[9]);
5077 __put_user(env->aregs[2], &gregs[10]);
5078 __put_user(env->aregs[3], &gregs[11]);
5079 __put_user(env->aregs[4], &gregs[12]);
5080 __put_user(env->aregs[5], &gregs[13]);
5081 __put_user(env->aregs[6], &gregs[14]);
5082 __put_user(env->aregs[7], &gregs[15]);
5083 __put_user(env->pc, &gregs[16]);
5084 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005085
Riku Voipio1d8b5122014-04-23 10:26:05 +03005086 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005087}
5088
Andreas Färber05390242012-02-25 03:37:53 +01005089static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005090 struct target_ucontext *uc,
5091 int *pd0)
5092{
5093 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005094 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005095
Riku Voipio1d8b5122014-04-23 10:26:05 +03005096 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005097 if (temp != TARGET_MCONTEXT_VERSION)
5098 goto badframe;
5099
5100 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005101 __get_user(env->dregs[0], &gregs[0]);
5102 __get_user(env->dregs[1], &gregs[1]);
5103 __get_user(env->dregs[2], &gregs[2]);
5104 __get_user(env->dregs[3], &gregs[3]);
5105 __get_user(env->dregs[4], &gregs[4]);
5106 __get_user(env->dregs[5], &gregs[5]);
5107 __get_user(env->dregs[6], &gregs[6]);
5108 __get_user(env->dregs[7], &gregs[7]);
5109 __get_user(env->aregs[0], &gregs[8]);
5110 __get_user(env->aregs[1], &gregs[9]);
5111 __get_user(env->aregs[2], &gregs[10]);
5112 __get_user(env->aregs[3], &gregs[11]);
5113 __get_user(env->aregs[4], &gregs[12]);
5114 __get_user(env->aregs[5], &gregs[13]);
5115 __get_user(env->aregs[6], &gregs[14]);
5116 __get_user(env->aregs[7], &gregs[15]);
5117 __get_user(env->pc, &gregs[16]);
5118 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005119 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5120
5121 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005122 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005123
5124badframe:
5125 return 1;
5126}
5127
Laurent Vivier492a8742009-08-03 16:12:17 +02005128static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005129 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005130 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005131{
Laurent Vivier71811552009-08-03 16:12:18 +02005132 struct target_rt_sigframe *frame;
5133 abi_ulong frame_addr;
5134 abi_ulong retcode_addr;
5135 abi_ulong info_addr;
5136 abi_ulong uc_addr;
5137 int err = 0;
5138 int i;
5139
5140 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005141 trace_user_setup_rt_frame(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005142 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5143 goto give_sigsegv;
5144
Riku Voipio1d8b5122014-04-23 10:26:05 +03005145 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005146
5147 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005148 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005149
5150 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005151 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005152
Peter Maydellf6c7a052015-01-08 12:19:48 +00005153 tswap_siginfo(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005154
5155 /* Create the ucontext */
5156
Riku Voipio1d8b5122014-04-23 10:26:05 +03005157 __put_user(0, &frame->uc.tuc_flags);
5158 __put_user(0, &frame->uc.tuc_link);
5159 __put_user(target_sigaltstack_used.ss_sp,
5160 &frame->uc.tuc_stack.ss_sp);
5161 __put_user(sas_ss_flags(env->aregs[7]),
5162 &frame->uc.tuc_stack.ss_flags);
5163 __put_user(target_sigaltstack_used.ss_size,
5164 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005165 err |= target_rt_setup_ucontext(&frame->uc, env);
5166
5167 if (err)
5168 goto give_sigsegv;
5169
5170 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005171 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005172 }
5173
5174 /* Set up to return from userspace. */
5175
5176 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005177 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005178
5179 /* moveq #,d0; notb d0; trap #0 */
5180
Riku Voipio1d8b5122014-04-23 10:26:05 +03005181 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005182 (uint32_t *)(frame->retcode + 0));
5183 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005184
5185 if (err)
5186 goto give_sigsegv;
5187
5188 /* Set up to return from userspace */
5189
5190 env->aregs[7] = frame_addr;
5191 env->pc = ka->_sa_handler;
5192
5193 unlock_user_struct(frame, frame_addr, 1);
5194 return;
5195
5196give_sigsegv:
5197 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005198 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005199}
5200
Andreas Färber05390242012-02-25 03:37:53 +01005201long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005202{
5203 struct target_sigframe *frame;
5204 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005205 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005206 sigset_t set;
5207 int d0, i;
5208
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005209 trace_user_do_sigreturn(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005210 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5211 goto badframe;
5212
5213 /* set blocked signals */
5214
Riku Voipiof5f601a2014-04-23 13:00:17 +03005215 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005216
5217 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005218 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005219 }
5220
5221 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005222 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005223
5224 /* restore registers */
5225
Riku Voipio016d2e12014-04-23 11:19:48 +03005226 restore_sigcontext(env, &frame->sc, &d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005227
5228 unlock_user_struct(frame, frame_addr, 0);
5229 return d0;
5230
5231badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005232 force_sig(TARGET_SIGSEGV);
5233 return 0;
5234}
5235
Andreas Färber05390242012-02-25 03:37:53 +01005236long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005237{
Laurent Vivier71811552009-08-03 16:12:18 +02005238 struct target_rt_sigframe *frame;
5239 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005240 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005241 sigset_t set;
5242 int d0;
5243
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005244 trace_user_do_rt_sigreturn(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005245 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5246 goto badframe;
5247
5248 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005249 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005250
5251 /* restore registers */
5252
5253 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5254 goto badframe;
5255
5256 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005257 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005258 0, get_sp_from_cpustate(env)) == -EFAULT)
5259 goto badframe;
5260
5261 unlock_user_struct(frame, frame_addr, 0);
5262 return d0;
5263
5264badframe:
5265 unlock_user_struct(frame, frame_addr, 0);
5266 force_sig(TARGET_SIGSEGV);
5267 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005268}
5269
Richard Henderson6049f4f2009-12-27 18:30:03 -08005270#elif defined(TARGET_ALPHA)
5271
5272struct target_sigcontext {
5273 abi_long sc_onstack;
5274 abi_long sc_mask;
5275 abi_long sc_pc;
5276 abi_long sc_ps;
5277 abi_long sc_regs[32];
5278 abi_long sc_ownedfp;
5279 abi_long sc_fpregs[32];
5280 abi_ulong sc_fpcr;
5281 abi_ulong sc_fp_control;
5282 abi_ulong sc_reserved1;
5283 abi_ulong sc_reserved2;
5284 abi_ulong sc_ssize;
5285 abi_ulong sc_sbase;
5286 abi_ulong sc_traparg_a0;
5287 abi_ulong sc_traparg_a1;
5288 abi_ulong sc_traparg_a2;
5289 abi_ulong sc_fp_trap_pc;
5290 abi_ulong sc_fp_trigger_sum;
5291 abi_ulong sc_fp_trigger_inst;
5292};
5293
5294struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005295 abi_ulong tuc_flags;
5296 abi_ulong tuc_link;
5297 abi_ulong tuc_osf_sigmask;
5298 target_stack_t tuc_stack;
5299 struct target_sigcontext tuc_mcontext;
5300 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005301};
5302
5303struct target_sigframe {
5304 struct target_sigcontext sc;
5305 unsigned int retcode[3];
5306};
5307
5308struct target_rt_sigframe {
5309 target_siginfo_t info;
5310 struct target_ucontext uc;
5311 unsigned int retcode[3];
5312};
5313
5314#define INSN_MOV_R30_R16 0x47fe0410
5315#define INSN_LDI_R0 0x201f0000
5316#define INSN_CALLSYS 0x00000083
5317
Riku Voipio41ecc722014-04-23 11:01:00 +03005318static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005319 abi_ulong frame_addr, target_sigset_t *set)
5320{
Riku Voipio41ecc722014-04-23 11:01:00 +03005321 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005322
Riku Voipio1d8b5122014-04-23 10:26:05 +03005323 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5324 __put_user(set->sig[0], &sc->sc_mask);
5325 __put_user(env->pc, &sc->sc_pc);
5326 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005327
5328 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005329 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005330 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005331 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005332
5333 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005334 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005335 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005336 __put_user(0, &sc->sc_fpregs[31]);
5337 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005338
Riku Voipio1d8b5122014-04-23 10:26:05 +03005339 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5340 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5341 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005342}
5343
Riku Voipio016d2e12014-04-23 11:19:48 +03005344static void restore_sigcontext(CPUAlphaState *env,
Andreas Färber05390242012-02-25 03:37:53 +01005345 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005346{
5347 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005348 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005349
Riku Voipio1d8b5122014-04-23 10:26:05 +03005350 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005351
5352 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005353 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005354 }
5355 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005356 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005357 }
5358
Riku Voipio1d8b5122014-04-23 10:26:05 +03005359 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005360 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005361}
5362
5363static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005364 CPUAlphaState *env,
5365 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005366{
5367 abi_ulong sp = env->ir[IR_SP];
5368
5369 /* This is the X/Open sanctioned signal stack switching. */
5370 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5371 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5372 }
5373 return (sp - framesize) & -32;
5374}
5375
5376static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005377 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005378{
5379 abi_ulong frame_addr, r26;
5380 struct target_sigframe *frame;
5381 int err = 0;
5382
5383 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005384 trace_user_setup_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005385 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5386 goto give_sigsegv;
5387 }
5388
Riku Voipio41ecc722014-04-23 11:01:00 +03005389 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005390
5391 if (ka->sa_restorer) {
5392 r26 = ka->sa_restorer;
5393 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005394 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5395 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5396 &frame->retcode[1]);
5397 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005398 /* imb() */
5399 r26 = frame_addr;
5400 }
5401
5402 unlock_user_struct(frame, frame_addr, 1);
5403
5404 if (err) {
5405 give_sigsegv:
5406 if (sig == TARGET_SIGSEGV) {
5407 ka->_sa_handler = TARGET_SIG_DFL;
5408 }
5409 force_sig(TARGET_SIGSEGV);
5410 }
5411
5412 env->ir[IR_RA] = r26;
5413 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5414 env->ir[IR_A0] = sig;
5415 env->ir[IR_A1] = 0;
5416 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5417 env->ir[IR_SP] = frame_addr;
5418}
5419
5420static void setup_rt_frame(int sig, struct target_sigaction *ka,
5421 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005422 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005423{
5424 abi_ulong frame_addr, r26;
5425 struct target_rt_sigframe *frame;
5426 int i, err = 0;
5427
5428 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005429 trace_user_setup_rt_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005430 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5431 goto give_sigsegv;
5432 }
5433
Peter Maydellf6c7a052015-01-08 12:19:48 +00005434 tswap_siginfo(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005435
Riku Voipio1d8b5122014-04-23 10:26:05 +03005436 __put_user(0, &frame->uc.tuc_flags);
5437 __put_user(0, &frame->uc.tuc_link);
5438 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5439 __put_user(target_sigaltstack_used.ss_sp,
5440 &frame->uc.tuc_stack.ss_sp);
5441 __put_user(sas_ss_flags(env->ir[IR_SP]),
5442 &frame->uc.tuc_stack.ss_flags);
5443 __put_user(target_sigaltstack_used.ss_size,
5444 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005445 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005446 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005447 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005448 }
5449
5450 if (ka->sa_restorer) {
5451 r26 = ka->sa_restorer;
5452 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005453 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5454 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5455 &frame->retcode[1]);
5456 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005457 /* imb(); */
5458 r26 = frame_addr;
5459 }
5460
5461 if (err) {
5462 give_sigsegv:
5463 if (sig == TARGET_SIGSEGV) {
5464 ka->_sa_handler = TARGET_SIG_DFL;
5465 }
5466 force_sig(TARGET_SIGSEGV);
5467 }
5468
5469 env->ir[IR_RA] = r26;
5470 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5471 env->ir[IR_A0] = sig;
5472 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5473 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5474 env->ir[IR_SP] = frame_addr;
5475}
5476
Andreas Färber05390242012-02-25 03:37:53 +01005477long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005478{
5479 struct target_sigcontext *sc;
5480 abi_ulong sc_addr = env->ir[IR_A0];
5481 target_sigset_t target_set;
5482 sigset_t set;
5483
5484 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5485 goto badframe;
5486 }
5487
5488 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005489 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005490
5491 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005492 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005493
Riku Voipio016d2e12014-04-23 11:19:48 +03005494 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005495 unlock_user_struct(sc, sc_addr, 0);
5496 return env->ir[IR_V0];
5497
5498 badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005499 force_sig(TARGET_SIGSEGV);
5500}
5501
Andreas Färber05390242012-02-25 03:37:53 +01005502long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005503{
5504 abi_ulong frame_addr = env->ir[IR_A0];
5505 struct target_rt_sigframe *frame;
5506 sigset_t set;
5507
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005508 trace_user_do_rt_sigreturn(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005509 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5510 goto badframe;
5511 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005512 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005513 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005514
Riku Voipio016d2e12014-04-23 11:19:48 +03005515 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005516 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005517 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005518 0, env->ir[IR_SP]) == -EFAULT) {
5519 goto badframe;
5520 }
5521
5522 unlock_user_struct(frame, frame_addr, 0);
5523 return env->ir[IR_V0];
5524
5525
5526 badframe:
5527 unlock_user_struct(frame, frame_addr, 0);
5528 force_sig(TARGET_SIGSEGV);
5529}
5530
Chen Gangbf0f60a2015-09-27 08:10:18 +08005531#elif defined(TARGET_TILEGX)
5532
5533struct target_sigcontext {
5534 union {
5535 /* General-purpose registers. */
5536 abi_ulong gregs[56];
5537 struct {
5538 abi_ulong __gregs[53];
5539 abi_ulong tp; /* Aliases gregs[TREG_TP]. */
5540 abi_ulong sp; /* Aliases gregs[TREG_SP]. */
5541 abi_ulong lr; /* Aliases gregs[TREG_LR]. */
5542 };
5543 };
5544 abi_ulong pc; /* Program counter. */
5545 abi_ulong ics; /* In Interrupt Critical Section? */
5546 abi_ulong faultnum; /* Fault number. */
5547 abi_ulong pad[5];
5548};
5549
5550struct target_ucontext {
5551 abi_ulong tuc_flags;
5552 abi_ulong tuc_link;
5553 target_stack_t tuc_stack;
5554 struct target_sigcontext tuc_mcontext;
5555 target_sigset_t tuc_sigmask; /* mask last for extensibility */
5556};
5557
5558struct target_rt_sigframe {
5559 unsigned char save_area[16]; /* caller save area */
5560 struct target_siginfo info;
5561 struct target_ucontext uc;
5562};
5563
5564static void setup_sigcontext(struct target_sigcontext *sc,
5565 CPUArchState *env, int signo)
5566{
5567 int i;
5568
5569 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5570 __put_user(env->regs[i], &sc->gregs[i]);
5571 }
5572
5573 __put_user(env->pc, &sc->pc);
5574 __put_user(0, &sc->ics);
5575 __put_user(signo, &sc->faultnum);
5576}
5577
5578static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
5579{
5580 int i;
5581
5582 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5583 __get_user(env->regs[i], &sc->gregs[i]);
5584 }
5585
5586 __get_user(env->pc, &sc->pc);
5587}
5588
5589static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
5590 size_t frame_size)
5591{
5592 unsigned long sp = env->regs[TILEGX_R_SP];
5593
5594 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
5595 return -1UL;
5596 }
5597
5598 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
5599 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5600 }
5601
5602 sp -= frame_size;
5603 sp &= -16UL;
5604 return sp;
5605}
5606
5607static void setup_rt_frame(int sig, struct target_sigaction *ka,
5608 target_siginfo_t *info,
5609 target_sigset_t *set, CPUArchState *env)
5610{
5611 abi_ulong frame_addr;
5612 struct target_rt_sigframe *frame;
5613 unsigned long restorer;
5614
5615 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005616 trace_user_setup_rt_frame(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005617 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5618 goto give_sigsegv;
5619 }
5620
5621 /* Always write at least the signal number for the stack backtracer. */
5622 if (ka->sa_flags & TARGET_SA_SIGINFO) {
5623 /* At sigreturn time, restore the callee-save registers too. */
5624 tswap_siginfo(&frame->info, info);
5625 /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
5626 } else {
5627 __put_user(info->si_signo, &frame->info.si_signo);
5628 }
5629
5630 /* Create the ucontext. */
5631 __put_user(0, &frame->uc.tuc_flags);
5632 __put_user(0, &frame->uc.tuc_link);
5633 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
5634 __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
5635 &frame->uc.tuc_stack.ss_flags);
5636 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
5637 setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
5638
5639 restorer = (unsigned long) do_rt_sigreturn;
5640 if (ka->sa_flags & TARGET_SA_RESTORER) {
5641 restorer = (unsigned long) ka->sa_restorer;
5642 }
5643 env->pc = (unsigned long) ka->_sa_handler;
5644 env->regs[TILEGX_R_SP] = (unsigned long) frame;
5645 env->regs[TILEGX_R_LR] = restorer;
5646 env->regs[0] = (unsigned long) sig;
5647 env->regs[1] = (unsigned long) &frame->info;
5648 env->regs[2] = (unsigned long) &frame->uc;
5649 /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
5650
5651 unlock_user_struct(frame, frame_addr, 1);
5652 return;
5653
5654give_sigsegv:
5655 if (sig == TARGET_SIGSEGV) {
5656 ka->_sa_handler = TARGET_SIG_DFL;
5657 }
5658 force_sig(TARGET_SIGSEGV /* , current */);
5659}
5660
5661long do_rt_sigreturn(CPUTLGState *env)
5662{
5663 abi_ulong frame_addr = env->regs[TILEGX_R_SP];
5664 struct target_rt_sigframe *frame;
5665 sigset_t set;
5666
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005667 trace_user_do_rt_sigreturn(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005668 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5669 goto badframe;
5670 }
5671 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
5672 do_sigprocmask(SIG_SETMASK, &set, NULL);
5673
5674 restore_sigcontext(env, &frame->uc.tuc_mcontext);
5675 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
5676 uc.tuc_stack),
5677 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
5678 goto badframe;
5679 }
5680
5681 unlock_user_struct(frame, frame_addr, 0);
5682 return env->regs[TILEGX_R_RE];
5683
5684
5685 badframe:
5686 unlock_user_struct(frame, frame_addr, 0);
5687 force_sig(TARGET_SIGSEGV);
5688}
5689
bellardb346ff42003-06-15 20:05:50 +00005690#else
5691
pbrook624f7972008-05-31 16:11:38 +00005692static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005693 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005694{
5695 fprintf(stderr, "setup_frame: not implemented\n");
5696}
5697
pbrook624f7972008-05-31 16:11:38 +00005698static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005699 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005700 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005701{
5702 fprintf(stderr, "setup_rt_frame: not implemented\n");
5703}
5704
Andreas Färber9349b4f2012-03-14 01:38:32 +01005705long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005706{
5707 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005708 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005709}
5710
Andreas Färber9349b4f2012-03-14 01:38:32 +01005711long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005712{
5713 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005714 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005715}
5716
bellard66fb9762003-03-23 01:06:05 +00005717#endif
5718
Andreas Färber9349b4f2012-03-14 01:38:32 +01005719void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005720{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005721 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005722 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005723 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005724 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005725 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005726 struct emulated_sigtable *k;
5727 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005728 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005729 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005730
pbrook624f7972008-05-31 16:11:38 +00005731 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005732 return;
5733
pbrook624f7972008-05-31 16:11:38 +00005734 /* FIXME: This is not threadsafe. */
5735 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005736 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5737 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005738 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005739 k++;
bellard31e31b82003-02-18 22:55:36 +00005740 }
5741 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005742 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005743 return;
bellard66fb9762003-03-23 01:06:05 +00005744
bellard31e31b82003-02-18 22:55:36 +00005745 handle_signal:
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005746 trace_user_handle_signal(cpu_env, sig);
bellard66fb9762003-03-23 01:06:05 +00005747 /* dequeue signal */
5748 q = k->first;
5749 k->first = q->next;
5750 if (!k->first)
5751 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005752
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005753 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005754 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005755 sa = NULL;
5756 handler = TARGET_SIG_IGN;
5757 } else {
5758 sa = &sigact_table[sig - 1];
5759 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005760 }
bellard66fb9762003-03-23 01:06:05 +00005761
Peter Maydella7ec0f92014-03-14 14:36:56 +00005762 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5763 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5764 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5765 * because it got a real MMU fault), and treat as if default handler.
5766 */
5767 handler = TARGET_SIG_DFL;
5768 }
5769
bellard66fb9762003-03-23 01:06:05 +00005770 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005771 /* default handler : ignore some signal. The other are job control or fatal */
5772 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5773 kill(getpid(),SIGSTOP);
5774 } else if (sig != TARGET_SIGCHLD &&
5775 sig != TARGET_SIGURG &&
5776 sig != TARGET_SIGWINCH &&
5777 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005778 force_sig(sig);
5779 }
5780 } else if (handler == TARGET_SIG_IGN) {
5781 /* ignore sig */
5782 } else if (handler == TARGET_SIG_ERR) {
5783 force_sig(sig);
5784 } else {
bellard9de5e442003-03-23 16:49:39 +00005785 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005786 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005787 /* SA_NODEFER indicates that the current signal should not be
5788 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005789 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005790 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005791
bellard9de5e442003-03-23 16:49:39 +00005792 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005793 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005794 /* save the previous blocked signal state to restore it at the
5795 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005796 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005797
bellardbc8a22c2003-03-30 21:02:40 +00005798 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005799#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005800 {
5801 CPUX86State *env = cpu_env;
5802 if (env->eflags & VM_MASK)
5803 save_v86_state(env);
5804 }
5805#endif
bellard9de5e442003-03-23 16:49:39 +00005806 /* prepare the stack frame of the virtual CPU */
Chen Gangd0924a22015-09-12 23:32:30 +08005807#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
Chen Gangbf0f60a2015-09-27 08:10:18 +08005808 || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)
Richard Hendersonff970902013-02-10 10:30:42 -08005809 /* These targets do not have traditional signals. */
5810 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5811#else
pbrook624f7972008-05-31 16:11:38 +00005812 if (sa->sa_flags & TARGET_SA_SIGINFO)
5813 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005814 else
pbrook624f7972008-05-31 16:11:38 +00005815 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005816#endif
pbrook624f7972008-05-31 16:11:38 +00005817 if (sa->sa_flags & TARGET_SA_RESETHAND)
5818 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005819 }
bellard66fb9762003-03-23 01:06:05 +00005820 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005821 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005822}