blob: 9d62e027e3f2061ff3d56a926085f265d1176c19 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
19#include <stdlib.h>
20#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000021#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000022#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000023#include <unistd.h>
bellard66fb9762003-03-23 01:06:05 +000024#include <errno.h>
bellard31e31b82003-02-18 22:55:36 +000025#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030026#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000027
bellard3ef693a2003-03-23 20:17:16 +000028#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000029#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000030#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000031
32//#define DEBUG_SIGNAL
33
blueswir1249c4c32008-10-05 11:09:37 +000034static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000035 .ss_sp = 0,
36 .ss_size = 0,
37 .ss_flags = TARGET_SS_DISABLE,
38};
39
pbrook624f7972008-05-31 16:11:38 +000040static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000041
ths5fafdf22007-09-16 21:08:06 +000042static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000043 void *puc);
44
Arnaud Patard3ca05582009-03-30 01:18:20 +020045static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000046 [SIGHUP] = TARGET_SIGHUP,
47 [SIGINT] = TARGET_SIGINT,
48 [SIGQUIT] = TARGET_SIGQUIT,
49 [SIGILL] = TARGET_SIGILL,
50 [SIGTRAP] = TARGET_SIGTRAP,
51 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000052/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000053 [SIGBUS] = TARGET_SIGBUS,
54 [SIGFPE] = TARGET_SIGFPE,
55 [SIGKILL] = TARGET_SIGKILL,
56 [SIGUSR1] = TARGET_SIGUSR1,
57 [SIGSEGV] = TARGET_SIGSEGV,
58 [SIGUSR2] = TARGET_SIGUSR2,
59 [SIGPIPE] = TARGET_SIGPIPE,
60 [SIGALRM] = TARGET_SIGALRM,
61 [SIGTERM] = TARGET_SIGTERM,
62#ifdef SIGSTKFLT
63 [SIGSTKFLT] = TARGET_SIGSTKFLT,
64#endif
65 [SIGCHLD] = TARGET_SIGCHLD,
66 [SIGCONT] = TARGET_SIGCONT,
67 [SIGSTOP] = TARGET_SIGSTOP,
68 [SIGTSTP] = TARGET_SIGTSTP,
69 [SIGTTIN] = TARGET_SIGTTIN,
70 [SIGTTOU] = TARGET_SIGTTOU,
71 [SIGURG] = TARGET_SIGURG,
72 [SIGXCPU] = TARGET_SIGXCPU,
73 [SIGXFSZ] = TARGET_SIGXFSZ,
74 [SIGVTALRM] = TARGET_SIGVTALRM,
75 [SIGPROF] = TARGET_SIGPROF,
76 [SIGWINCH] = TARGET_SIGWINCH,
77 [SIGIO] = TARGET_SIGIO,
78 [SIGPWR] = TARGET_SIGPWR,
79 [SIGSYS] = TARGET_SIGSYS,
80 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000081 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080082 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000083 To fix this properly we need to do manual signal delivery multiplexed
84 over a single host signal. */
85 [__SIGRTMIN] = __SIGRTMAX,
86 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000087};
Arnaud Patard3ca05582009-03-30 01:18:20 +020088static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000089
thsa04e1342007-09-27 13:57:58 +000090static inline int on_sig_stack(unsigned long sp)
91{
92 return (sp - target_sigaltstack_used.ss_sp
93 < target_sigaltstack_used.ss_size);
94}
95
96static inline int sas_ss_flags(unsigned long sp)
97{
98 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
99 : on_sig_stack(sp) ? SS_ONSTACK : 0);
100}
101
pbrook1d9d8b52009-04-16 15:17:02 +0000102int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000103{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100104 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000105 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000106 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000107}
108
pbrook4cb05962008-05-30 18:05:19 +0000109int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000110{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100111 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000112 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000113 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000114}
115
Anthony Liguoric227f092009-10-01 16:12:16 -0500116static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000117{
118 memset(set, 0, sizeof(*set));
119}
120
Anthony Liguoric227f092009-10-01 16:12:16 -0500121static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000122{
123 signum--;
124 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
125 set->sig[signum / TARGET_NSIG_BPW] |= mask;
126}
127
Anthony Liguoric227f092009-10-01 16:12:16 -0500128static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000129{
130 signum--;
131 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
132 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
133}
134
Anthony Liguoric227f092009-10-01 16:12:16 -0500135static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000136 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000137{
138 int i;
pbrookf5545b52008-05-30 22:37:07 +0000139 target_sigemptyset(d);
140 for (i = 1; i <= TARGET_NSIG; i++) {
141 if (sigismember(s, i)) {
142 target_sigaddset(d, host_to_target_signal(i));
143 }
bellard9e5f5282003-07-13 17:33:54 +0000144 }
bellard66fb9762003-03-23 01:06:05 +0000145}
146
Anthony Liguoric227f092009-10-01 16:12:16 -0500147void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000148{
Anthony Liguoric227f092009-10-01 16:12:16 -0500149 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000150 int i;
151
152 host_to_target_sigset_internal(&d1, s);
153 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200154 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000155}
156
blueswir18fcd3692008-08-17 20:26:25 +0000157static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500158 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000159{
160 int i;
pbrookf5545b52008-05-30 22:37:07 +0000161 sigemptyset(d);
162 for (i = 1; i <= TARGET_NSIG; i++) {
163 if (target_sigismember(s, i)) {
164 sigaddset(d, target_to_host_signal(i));
165 }
166 }
bellard66fb9762003-03-23 01:06:05 +0000167}
168
Anthony Liguoric227f092009-10-01 16:12:16 -0500169void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000170{
Anthony Liguoric227f092009-10-01 16:12:16 -0500171 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000172 int i;
173
174 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200175 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000176 target_to_host_sigset_internal(d, &s1);
177}
ths3b46e622007-09-17 08:09:54 +0000178
blueswir1992f48a2007-10-14 16:27:31 +0000179void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000180 const sigset_t *sigset)
181{
Anthony Liguoric227f092009-10-01 16:12:16 -0500182 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000183 host_to_target_sigset(&d, sigset);
184 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000185}
186
ths5fafdf22007-09-16 21:08:06 +0000187void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000188 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000189{
Anthony Liguoric227f092009-10-01 16:12:16 -0500190 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000191 int i;
192
193 d.sig[0] = *old_sigset;
194 for(i = 1;i < TARGET_NSIG_WORDS; i++)
195 d.sig[i] = 0;
196 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000197}
198
Alex Barcelo1c275922014-03-14 14:36:55 +0000199/* Wrapper for sigprocmask function
200 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
201 * are host signal set, not guest ones. This wraps the sigprocmask host calls
202 * that should be protected (calls originated from guest)
203 */
204int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
205{
Peter Maydella7ec0f92014-03-14 14:36:56 +0000206 int ret;
207 sigset_t val;
208 sigset_t *temp = NULL;
209 CPUState *cpu = thread_cpu;
210 TaskState *ts = (TaskState *)cpu->opaque;
211 bool segv_was_blocked = ts->sigsegv_blocked;
212
213 if (set) {
214 bool has_sigsegv = sigismember(set, SIGSEGV);
215 val = *set;
216 temp = &val;
217
218 sigdelset(temp, SIGSEGV);
219
220 switch (how) {
221 case SIG_BLOCK:
222 if (has_sigsegv) {
223 ts->sigsegv_blocked = true;
224 }
225 break;
226 case SIG_UNBLOCK:
227 if (has_sigsegv) {
228 ts->sigsegv_blocked = false;
229 }
230 break;
231 case SIG_SETMASK:
232 ts->sigsegv_blocked = has_sigsegv;
233 break;
234 default:
235 g_assert_not_reached();
236 }
237 }
238
239 ret = sigprocmask(how, temp, oldset);
240
241 if (oldset && segv_was_blocked) {
242 sigaddset(oldset, SIGSEGV);
243 }
244
245 return ret;
Alex Barcelo1c275922014-03-14 14:36:55 +0000246}
247
bellard9de5e442003-03-23 16:49:39 +0000248/* siginfo conversion */
249
Anthony Liguoric227f092009-10-01 16:12:16 -0500250static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000251 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000252{
Richard Hendersona05c6402012-09-15 11:34:20 -0700253 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000254 tinfo->si_signo = sig;
255 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000256 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700257
258 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
259 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
260 /* Should never come here, but who knows. The information for
261 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000262 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700263 } else if (sig == TARGET_SIGIO) {
264 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000265 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700266 } else if (sig == TARGET_SIGCHLD) {
267 tinfo->_sifields._sigchld._pid = info->si_pid;
268 tinfo->_sifields._sigchld._uid = info->si_uid;
269 tinfo->_sifields._sigchld._status
270 = host_to_target_waitstatus(info->si_status);
271 tinfo->_sifields._sigchld._utime = info->si_utime;
272 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000273 } else if (sig >= TARGET_SIGRTMIN) {
274 tinfo->_sifields._rt._pid = info->si_pid;
275 tinfo->_sifields._rt._uid = info->si_uid;
276 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700277 tinfo->_sifields._rt._sigval.sival_ptr
278 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000279 }
bellard66fb9762003-03-23 01:06:05 +0000280}
281
Anthony Liguoric227f092009-10-01 16:12:16 -0500282static void tswap_siginfo(target_siginfo_t *tinfo,
283 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000284{
Richard Hendersona05c6402012-09-15 11:34:20 -0700285 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000286 tinfo->si_signo = tswap32(sig);
287 tinfo->si_errno = tswap32(info->si_errno);
288 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700289
290 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
291 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
292 tinfo->_sifields._sigfault._addr
293 = tswapal(info->_sifields._sigfault._addr);
294 } else if (sig == TARGET_SIGIO) {
295 tinfo->_sifields._sigpoll._band
296 = tswap32(info->_sifields._sigpoll._band);
297 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
298 } else if (sig == TARGET_SIGCHLD) {
299 tinfo->_sifields._sigchld._pid
300 = tswap32(info->_sifields._sigchld._pid);
301 tinfo->_sifields._sigchld._uid
302 = tswap32(info->_sifields._sigchld._uid);
303 tinfo->_sifields._sigchld._status
304 = tswap32(info->_sifields._sigchld._status);
305 tinfo->_sifields._sigchld._utime
306 = tswapal(info->_sifields._sigchld._utime);
307 tinfo->_sifields._sigchld._stime
308 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000309 } else if (sig >= TARGET_SIGRTMIN) {
310 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
311 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700312 tinfo->_sifields._rt._sigval.sival_ptr
313 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000314 }
315}
316
317
Anthony Liguoric227f092009-10-01 16:12:16 -0500318void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000319{
320 host_to_target_siginfo_noswap(tinfo, info);
321 tswap_siginfo(tinfo, tinfo);
322}
323
324/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000325/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500326void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000327{
328 info->si_signo = tswap32(tinfo->si_signo);
329 info->si_errno = tswap32(tinfo->si_errno);
330 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000331 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
332 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000333 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200334 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000335}
336
aurel32ca587a82008-12-18 22:44:13 +0000337static int fatal_signal (int sig)
338{
339 switch (sig) {
340 case TARGET_SIGCHLD:
341 case TARGET_SIGURG:
342 case TARGET_SIGWINCH:
343 /* Ignored by default. */
344 return 0;
345 case TARGET_SIGCONT:
346 case TARGET_SIGSTOP:
347 case TARGET_SIGTSTP:
348 case TARGET_SIGTTIN:
349 case TARGET_SIGTTOU:
350 /* Job control signals. */
351 return 0;
352 default:
353 return 1;
354 }
355}
356
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300357/* returns 1 if given signal should dump core if not handled */
358static int core_dump_signal(int sig)
359{
360 switch (sig) {
361 case TARGET_SIGABRT:
362 case TARGET_SIGFPE:
363 case TARGET_SIGILL:
364 case TARGET_SIGQUIT:
365 case TARGET_SIGSEGV:
366 case TARGET_SIGTRAP:
367 case TARGET_SIGBUS:
368 return (1);
369 default:
370 return (0);
371 }
372}
373
bellard31e31b82003-02-18 22:55:36 +0000374void signal_init(void)
375{
376 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000377 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000378 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000379 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000380
bellard9e5f5282003-07-13 17:33:54 +0000381 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200382 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000383 if (host_to_target_signal_table[i] == 0)
384 host_to_target_signal_table[i] = i;
385 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200386 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000387 j = host_to_target_signal_table[i];
388 target_to_host_signal_table[j] = i;
389 }
ths3b46e622007-09-17 08:09:54 +0000390
bellard9de5e442003-03-23 16:49:39 +0000391 /* set all host signal handlers. ALL signals are blocked during
392 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000393 memset(sigact_table, 0, sizeof(sigact_table));
394
bellard9de5e442003-03-23 16:49:39 +0000395 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000396 act.sa_flags = SA_SIGINFO;
397 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000398 for(i = 1; i <= TARGET_NSIG; i++) {
399 host_sig = target_to_host_signal(i);
400 sigaction(host_sig, NULL, &oact);
401 if (oact.sa_sigaction == (void *)SIG_IGN) {
402 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
403 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
404 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
405 }
406 /* If there's already a handler installed then something has
407 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000408 /* Install some handlers for our own use. We need at least
409 SIGSEGV and SIGBUS, to detect exceptions. We can not just
410 trap all signals because it affects syscall interrupt
411 behavior. But do trap all default-fatal signals. */
412 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000413 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000414 }
bellard31e31b82003-02-18 22:55:36 +0000415}
416
bellard66fb9762003-03-23 01:06:05 +0000417/* signal queue handling */
418
Andreas Färber9349b4f2012-03-14 01:38:32 +0100419static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000420{
Andreas Färber0429a972013-08-26 18:14:44 +0200421 CPUState *cpu = ENV_GET_CPU(env);
422 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000423 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000424 if (!q)
425 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000426 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000427 return q;
428}
429
Andreas Färber9349b4f2012-03-14 01:38:32 +0100430static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000431{
Andreas Färber0429a972013-08-26 18:14:44 +0200432 CPUState *cpu = ENV_GET_CPU(env);
433 TaskState *ts = cpu->opaque;
434
pbrook624f7972008-05-31 16:11:38 +0000435 q->next = ts->first_free;
436 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000437}
438
bellard9de5e442003-03-23 16:49:39 +0000439/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200440static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000441{
Andreas Färber0429a972013-08-26 18:14:44 +0200442 CPUState *cpu = thread_cpu;
443 CPUArchState *env = cpu->env_ptr;
444 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300445 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000446 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200447 host_sig = target_to_host_signal(target_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200448 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000449
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300450 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200451 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300452 stop_all_tasks();
453 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200454 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300455 }
456 if (core_dumped) {
457 /* we already dumped the core of target process, we don't want
458 * a coredump of qemu itself */
459 struct rlimit nodump;
460 getrlimit(RLIMIT_CORE, &nodump);
461 nodump.rlim_cur=0;
462 setrlimit(RLIMIT_CORE, &nodump);
463 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200464 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300465 }
466
Stefan Weil0c587512011-04-28 17:20:32 +0200467 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000468 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
469 * a negative value. To get the proper exit code we need to
470 * actually die from an uncaught signal. Here the default signal
471 * handler is installed, we send ourself a signal and we wait for
472 * it to arrive. */
473 sigfillset(&act.sa_mask);
474 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000475 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000476 sigaction(host_sig, &act, NULL);
477
478 /* For some reason raise(host_sig) doesn't send the signal when
479 * statically linked on x86-64. */
480 kill(getpid(), host_sig);
481
482 /* Make sure the signal isn't masked (just reuse the mask inside
483 of act) */
484 sigdelset(&act.sa_mask, host_sig);
485 sigsuspend(&act.sa_mask);
486
487 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000488 abort();
bellard66fb9762003-03-23 01:06:05 +0000489}
490
bellard9de5e442003-03-23 16:49:39 +0000491/* queue a signal so that it will be send to the virtual CPU as soon
492 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100493int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000494{
Andreas Färber0429a972013-08-26 18:14:44 +0200495 CPUState *cpu = ENV_GET_CPU(env);
496 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000497 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000498 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000499 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000500 int queue;
bellard66fb9762003-03-23 01:06:05 +0000501
bellard9de5e442003-03-23 16:49:39 +0000502#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000503 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000504 sig);
bellard66fb9762003-03-23 01:06:05 +0000505#endif
pbrook624f7972008-05-31 16:11:38 +0000506 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000507 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000508 handler = sigact_table[sig - 1]._sa_handler;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000509
510 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
511 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
512 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
513 * because it got a real MMU fault). A blocked SIGSEGV in that
514 * situation is treated as if using the default handler. This is
515 * not correct if some other process has randomly sent us a SIGSEGV
516 * via kill(), but that is not easy to distinguish at this point,
517 * so we assume it doesn't happen.
518 */
519 handler = TARGET_SIG_DFL;
520 }
521
aurel32ca587a82008-12-18 22:44:13 +0000522 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000523 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
524 kill(getpid(),SIGSTOP);
525 return 0;
526 } else
bellard66fb9762003-03-23 01:06:05 +0000527 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000528 if (sig != TARGET_SIGCHLD &&
529 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000530 sig != TARGET_SIGWINCH &&
531 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000532 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000533 } else {
534 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000535 }
aurel32ca587a82008-12-18 22:44:13 +0000536 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000537 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000538 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000539 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000540 force_sig(sig);
541 } else {
bellard9de5e442003-03-23 16:49:39 +0000542 pq = &k->first;
543 if (sig < TARGET_SIGRTMIN) {
544 /* if non real time signal, we queue exactly one signal */
545 if (!k->pending)
546 q = &k->info;
547 else
548 return 0;
549 } else {
550 if (!k->pending) {
551 /* first signal */
552 q = &k->info;
553 } else {
pbrook624f7972008-05-31 16:11:38 +0000554 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000555 if (!q)
556 return -EAGAIN;
557 while (*pq != NULL)
558 pq = &(*pq)->next;
559 }
560 }
561 *pq = q;
562 q->info = *info;
563 q->next = NULL;
564 k->pending = 1;
565 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000566 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000567 return 1; /* indicates that the signal was queued */
568 }
569}
570
ths5fafdf22007-09-16 21:08:06 +0000571static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000572 void *puc)
573{
Andreas Färbera2247f82013-06-09 19:47:04 +0200574 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000575 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500576 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000577
578 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000579 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000580 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000581 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000582 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000583 return;
584 }
585
586 /* get target signal number */
587 sig = host_to_target_signal(host_signum);
588 if (sig < 1 || sig > TARGET_NSIG)
589 return;
590#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000591 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000592#endif
593 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200594 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000595 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200596 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000597 }
bellard31e31b82003-02-18 22:55:36 +0000598}
599
ths0da46a62007-10-20 20:23:07 +0000600/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000601/* compare linux/kernel/signal.c:do_sigaltstack() */
602abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000603{
604 int ret;
605 struct target_sigaltstack oss;
606
607 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000608 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000609 {
610 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
611 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
612 __put_user(sas_ss_flags(sp), &oss.ss_flags);
613 }
614
bellard579a97f2007-11-11 14:26:47 +0000615 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000616 {
bellard579a97f2007-11-11 14:26:47 +0000617 struct target_sigaltstack *uss;
618 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500619 size_t minstacksize = TARGET_MINSIGSTKSZ;
620
621#if defined(TARGET_PPC64)
622 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
623 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
624 if (get_ppc64_abi(image) > 1) {
625 minstacksize = 4096;
626 }
627#endif
thsa04e1342007-09-27 13:57:58 +0000628
ths0da46a62007-10-20 20:23:07 +0000629 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300630 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000631 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300632 }
633 __get_user(ss.ss_sp, &uss->ss_sp);
634 __get_user(ss.ss_size, &uss->ss_size);
635 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000636 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000637
ths0da46a62007-10-20 20:23:07 +0000638 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000639 if (on_sig_stack(sp))
640 goto out;
641
ths0da46a62007-10-20 20:23:07 +0000642 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000643 if (ss.ss_flags != TARGET_SS_DISABLE
644 && ss.ss_flags != TARGET_SS_ONSTACK
645 && ss.ss_flags != 0)
646 goto out;
647
648 if (ss.ss_flags == TARGET_SS_DISABLE) {
649 ss.ss_size = 0;
650 ss.ss_sp = 0;
651 } else {
ths0da46a62007-10-20 20:23:07 +0000652 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500653 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000654 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500655 }
thsa04e1342007-09-27 13:57:58 +0000656 }
657
658 target_sigaltstack_used.ss_sp = ss.ss_sp;
659 target_sigaltstack_used.ss_size = ss.ss_size;
660 }
661
bellard579a97f2007-11-11 14:26:47 +0000662 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000663 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000664 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000665 goto out;
thsa04e1342007-09-27 13:57:58 +0000666 }
667
668 ret = 0;
669out:
670 return ret;
671}
672
ths0da46a62007-10-20 20:23:07 +0000673/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000674int do_sigaction(int sig, const struct target_sigaction *act,
675 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000676{
pbrook624f7972008-05-31 16:11:38 +0000677 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000678 struct sigaction act1;
679 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000680 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000681
ths2a913eb2008-11-27 15:46:25 +0000682 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000683 return -EINVAL;
684 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000685#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000686 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
687 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000688#endif
689 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800690 __put_user(k->_sa_handler, &oact->_sa_handler);
691 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000692#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800693 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000694#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800695 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000696 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000697 }
698 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000699 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800700 __get_user(k->_sa_handler, &act->_sa_handler);
701 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000702#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800703 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000704#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800705 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000706 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000707
708 /* we update the host linux signal state */
709 host_sig = target_to_host_signal(sig);
710 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
711 sigfillset(&act1.sa_mask);
712 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000713 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000714 act1.sa_flags |= SA_RESTART;
715 /* NOTE: it is important to update the host kernel signal
716 ignore state to avoid getting unexpected interrupted
717 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000718 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000719 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000720 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000721 if (fatal_signal (sig))
722 act1.sa_sigaction = host_signal_handler;
723 else
724 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000725 } else {
726 act1.sa_sigaction = host_signal_handler;
727 }
ths0da46a62007-10-20 20:23:07 +0000728 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000729 }
bellard66fb9762003-03-23 01:06:05 +0000730 }
ths0da46a62007-10-20 20:23:07 +0000731 return ret;
bellard66fb9762003-03-23 01:06:05 +0000732}
bellard31e31b82003-02-18 22:55:36 +0000733
bellard459a4012007-11-11 19:45:10 +0000734#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000735
736/* from the Linux kernel */
737
738struct target_fpreg {
739 uint16_t significand[4];
740 uint16_t exponent;
741};
742
743struct target_fpxreg {
744 uint16_t significand[4];
745 uint16_t exponent;
746 uint16_t padding[3];
747};
748
749struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000750 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000751};
752
753struct target_fpstate {
754 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000755 abi_ulong cw;
756 abi_ulong sw;
757 abi_ulong tag;
758 abi_ulong ipoff;
759 abi_ulong cssel;
760 abi_ulong dataoff;
761 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000762 struct target_fpreg _st[8];
763 uint16_t status;
764 uint16_t magic; /* 0xffff = regular FPU data only */
765
766 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000767 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
768 abi_ulong mxcsr;
769 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000770 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
771 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000772 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000773};
774
775#define X86_FXSR_MAGIC 0x0000
776
777struct target_sigcontext {
778 uint16_t gs, __gsh;
779 uint16_t fs, __fsh;
780 uint16_t es, __esh;
781 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000782 abi_ulong edi;
783 abi_ulong esi;
784 abi_ulong ebp;
785 abi_ulong esp;
786 abi_ulong ebx;
787 abi_ulong edx;
788 abi_ulong ecx;
789 abi_ulong eax;
790 abi_ulong trapno;
791 abi_ulong err;
792 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000793 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000794 abi_ulong eflags;
795 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000796 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000797 abi_ulong fpstate; /* pointer */
798 abi_ulong oldmask;
799 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000800};
801
bellard66fb9762003-03-23 01:06:05 +0000802struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000803 abi_ulong tuc_flags;
804 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500805 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000806 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500807 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000808};
809
810struct sigframe
811{
blueswir1992f48a2007-10-14 16:27:31 +0000812 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000813 int sig;
814 struct target_sigcontext sc;
815 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000816 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000817 char retcode[8];
818};
819
820struct rt_sigframe
821{
blueswir1992f48a2007-10-14 16:27:31 +0000822 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000823 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000824 abi_ulong pinfo;
825 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000826 struct target_siginfo info;
827 struct target_ucontext uc;
828 struct target_fpstate fpstate;
829 char retcode[8];
830};
831
832/*
833 * Set up a signal frame.
834 */
835
bellard66fb9762003-03-23 01:06:05 +0000836/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300837static void setup_sigcontext(struct target_sigcontext *sc,
838 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
839 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000840{
Andreas Färber27103422013-08-26 08:31:06 +0200841 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200842 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000843
bellard579a97f2007-11-11 14:26:47 +0000844 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300845 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
846 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
847 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
848 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
849 __put_user(env->regs[R_EDI], &sc->edi);
850 __put_user(env->regs[R_ESI], &sc->esi);
851 __put_user(env->regs[R_EBP], &sc->ebp);
852 __put_user(env->regs[R_ESP], &sc->esp);
853 __put_user(env->regs[R_EBX], &sc->ebx);
854 __put_user(env->regs[R_EDX], &sc->edx);
855 __put_user(env->regs[R_ECX], &sc->ecx);
856 __put_user(env->regs[R_EAX], &sc->eax);
857 __put_user(cs->exception_index, &sc->trapno);
858 __put_user(env->error_code, &sc->err);
859 __put_user(env->eip, &sc->eip);
860 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
861 __put_user(env->eflags, &sc->eflags);
862 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
863 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000864
bellard28be6232007-11-11 22:23:38 +0000865 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000866 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000867 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300868 __put_user(magic, &fpstate->magic);
869 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000870
bellard66fb9762003-03-23 01:06:05 +0000871 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300872 __put_user(mask, &sc->oldmask);
873 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000874}
875
876/*
877 * Determine which stack to use..
878 */
879
bellard579a97f2007-11-11 14:26:47 +0000880static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000881get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000882{
883 unsigned long esp;
884
885 /* Default to using normal stack */
886 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000887 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000888 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000889 if (sas_ss_flags(esp) == 0)
890 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
891 }
bellard66fb9762003-03-23 01:06:05 +0000892
893 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000894 else
bellarda52c7572003-06-21 13:14:12 +0000895 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000896 !(ka->sa_flags & TARGET_SA_RESTORER) &&
897 ka->sa_restorer) {
898 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000899 }
bellard579a97f2007-11-11 14:26:47 +0000900 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000901}
902
bellard579a97f2007-11-11 14:26:47 +0000903/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000904static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500905 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000906{
bellard579a97f2007-11-11 14:26:47 +0000907 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000908 struct sigframe *frame;
Riku Voipio7df2fa32014-04-23 10:34:53 +0300909 int i;
bellard66fb9762003-03-23 01:06:05 +0000910
bellard579a97f2007-11-11 14:26:47 +0000911 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000912
bellard579a97f2007-11-11 14:26:47 +0000913 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000914 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000915
Peter Maydellb6e2c932015-01-08 12:19:43 +0000916 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000917
bellard28be6232007-11-11 22:23:38 +0000918 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
919 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000920
Riku Voipio7df2fa32014-04-23 10:34:53 +0300921 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
922 __put_user(set->sig[i], &frame->extramask[i - 1]);
923 }
bellard66fb9762003-03-23 01:06:05 +0000924
925 /* Set up to return from userspace. If provided, use a stub
926 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000927 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300928 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000929 } else {
bellard775b58d2007-11-11 16:22:17 +0000930 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000931 abi_ulong retcode_addr;
932 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300933 __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000934 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000935 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300936 __put_user(val16, (uint16_t *)(frame->retcode+0));
937 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000938 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300939 __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000940 }
941
bellard66fb9762003-03-23 01:06:05 +0000942
943 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000944 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000945 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000946
947 cpu_x86_load_seg(env, R_DS, __USER_DS);
948 cpu_x86_load_seg(env, R_ES, __USER_DS);
949 cpu_x86_load_seg(env, R_SS, __USER_DS);
950 cpu_x86_load_seg(env, R_CS, __USER_CS);
951 env->eflags &= ~TF_MASK;
952
bellard579a97f2007-11-11 14:26:47 +0000953 unlock_user_struct(frame, frame_addr, 1);
954
bellard66fb9762003-03-23 01:06:05 +0000955 return;
956
957give_sigsegv:
958 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000959 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000960 force_sig(TARGET_SIGSEGV /* , current */);
961}
962
bellard579a97f2007-11-11 14:26:47 +0000963/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000964static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500965 target_siginfo_t *info,
966 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000967{
bellard28be6232007-11-11 22:23:38 +0000968 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000969 struct rt_sigframe *frame;
Riku Voipio0188fad2014-04-23 13:34:15 +0300970 int i;
bellard66fb9762003-03-23 01:06:05 +0000971
bellard579a97f2007-11-11 14:26:47 +0000972 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000973
bellard579a97f2007-11-11 14:26:47 +0000974 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000975 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000976
Peter Maydellb6e2c932015-01-08 12:19:43 +0000977 __put_user(sig, &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000978 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300979 __put_user(addr, &frame->pinfo);
bellard28be6232007-11-11 22:23:38 +0000980 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300981 __put_user(addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +0000982 tswap_siginfo(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +0000983
984 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300985 __put_user(0, &frame->uc.tuc_flags);
986 __put_user(0, &frame->uc.tuc_link);
987 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
988 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
989 &frame->uc.tuc_stack.ss_flags);
990 __put_user(target_sigaltstack_used.ss_size,
991 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +0300992 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
993 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
994
Riku Voipio0188fad2014-04-23 13:34:15 +0300995 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
996 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
997 }
bellard66fb9762003-03-23 01:06:05 +0000998
999 /* Set up to return from userspace. If provided, use a stub
1000 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00001001 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001002 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001003 } else {
bellard775b58d2007-11-11 16:22:17 +00001004 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +00001005 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001006 __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001007 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001008 __put_user(0xb8, (char *)(frame->retcode+0));
1009 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +00001010 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001011 __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +00001012 }
1013
bellard66fb9762003-03-23 01:06:05 +00001014 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +00001015 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +00001016 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001017
1018 cpu_x86_load_seg(env, R_DS, __USER_DS);
1019 cpu_x86_load_seg(env, R_ES, __USER_DS);
1020 cpu_x86_load_seg(env, R_SS, __USER_DS);
1021 cpu_x86_load_seg(env, R_CS, __USER_CS);
1022 env->eflags &= ~TF_MASK;
1023
bellard579a97f2007-11-11 14:26:47 +00001024 unlock_user_struct(frame, frame_addr, 1);
1025
bellard66fb9762003-03-23 01:06:05 +00001026 return;
1027
1028give_sigsegv:
1029 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001030 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001031 force_sig(TARGET_SIGSEGV /* , current */);
1032}
1033
1034static int
1035restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1036{
1037 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001038 abi_ulong fpstate_addr;
1039 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001040
bellard28be6232007-11-11 22:23:38 +00001041 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1042 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1043 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1044 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001045
bellard28be6232007-11-11 22:23:38 +00001046 env->regs[R_EDI] = tswapl(sc->edi);
1047 env->regs[R_ESI] = tswapl(sc->esi);
1048 env->regs[R_EBP] = tswapl(sc->ebp);
1049 env->regs[R_ESP] = tswapl(sc->esp);
1050 env->regs[R_EBX] = tswapl(sc->ebx);
1051 env->regs[R_EDX] = tswapl(sc->edx);
1052 env->regs[R_ECX] = tswapl(sc->ecx);
1053 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001054
Mike McCormack9a826d72011-06-01 15:14:37 +09001055 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1056 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001057
bellard28be6232007-11-11 22:23:38 +00001058 tmpflags = tswapl(sc->eflags);
1059 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1060 // regs->orig_eax = -1; /* disable syscall checks */
1061
1062 fpstate_addr = tswapl(sc->fpstate);
1063 if (fpstate_addr != 0) {
1064 if (!access_ok(VERIFY_READ, fpstate_addr,
1065 sizeof(struct target_fpstate)))
1066 goto badframe;
1067 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001068 }
1069
bellard28be6232007-11-11 22:23:38 +00001070 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001071 return err;
bellard66fb9762003-03-23 01:06:05 +00001072badframe:
1073 return 1;
bellard66fb9762003-03-23 01:06:05 +00001074}
1075
1076long do_sigreturn(CPUX86State *env)
1077{
bellard579a97f2007-11-11 14:26:47 +00001078 struct sigframe *frame;
1079 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001080 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001081 sigset_t set;
1082 int eax, i;
1083
bellard447db212003-05-10 15:10:36 +00001084#if defined(DEBUG_SIGNAL)
1085 fprintf(stderr, "do_sigreturn\n");
1086#endif
bellard579a97f2007-11-11 14:26:47 +00001087 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1088 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001089 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001090 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001091 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001092 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001093 }
bellard66fb9762003-03-23 01:06:05 +00001094
bellard92319442004-06-19 16:58:13 +00001095 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001096 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001097
bellard66fb9762003-03-23 01:06:05 +00001098 /* restore registers */
1099 if (restore_sigcontext(env, &frame->sc, &eax))
1100 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001101 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001102 return eax;
1103
1104badframe:
bellard579a97f2007-11-11 14:26:47 +00001105 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001106 force_sig(TARGET_SIGSEGV);
1107 return 0;
1108}
1109
1110long do_rt_sigreturn(CPUX86State *env)
1111{
bellard28be6232007-11-11 22:23:38 +00001112 abi_ulong frame_addr;
1113 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001114 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001115 int eax;
1116
bellard28be6232007-11-11 22:23:38 +00001117 frame_addr = env->regs[R_ESP] - 4;
1118 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1119 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001120 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001121 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001122
bellardb8076a72005-04-07 22:20:31 +00001123 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001124 goto badframe;
1125
bellard28be6232007-11-11 22:23:38 +00001126 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1127 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001128 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001129
bellard28be6232007-11-11 22:23:38 +00001130 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001131 return eax;
1132
1133badframe:
bellard28be6232007-11-11 22:23:38 +00001134 unlock_user_struct(frame, frame_addr, 0);
1135 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001136 return 0;
1137}
1138
Andreas Schwab1744aea2013-09-03 20:12:16 +01001139#elif defined(TARGET_AARCH64)
1140
1141struct target_sigcontext {
1142 uint64_t fault_address;
1143 /* AArch64 registers */
1144 uint64_t regs[31];
1145 uint64_t sp;
1146 uint64_t pc;
1147 uint64_t pstate;
1148 /* 4K reserved for FP/SIMD state and future expansion */
1149 char __reserved[4096] __attribute__((__aligned__(16)));
1150};
1151
1152struct target_ucontext {
1153 abi_ulong tuc_flags;
1154 abi_ulong tuc_link;
1155 target_stack_t tuc_stack;
1156 target_sigset_t tuc_sigmask;
1157 /* glibc uses a 1024-bit sigset_t */
1158 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1159 /* last for future expansion */
1160 struct target_sigcontext tuc_mcontext;
1161};
1162
1163/*
1164 * Header to be used at the beginning of structures extending the user
1165 * context. Such structures must be placed after the rt_sigframe on the stack
1166 * and be 16-byte aligned. The last structure must be a dummy one with the
1167 * magic and size set to 0.
1168 */
1169struct target_aarch64_ctx {
1170 uint32_t magic;
1171 uint32_t size;
1172};
1173
1174#define TARGET_FPSIMD_MAGIC 0x46508001
1175
1176struct target_fpsimd_context {
1177 struct target_aarch64_ctx head;
1178 uint32_t fpsr;
1179 uint32_t fpcr;
1180 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1181};
1182
1183/*
1184 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1185 * user space as it will change with the addition of new context. User space
1186 * should check the magic/size information.
1187 */
1188struct target_aux_context {
1189 struct target_fpsimd_context fpsimd;
1190 /* additional context to be added before "end" */
1191 struct target_aarch64_ctx end;
1192};
1193
1194struct target_rt_sigframe {
1195 struct target_siginfo info;
1196 struct target_ucontext uc;
1197 uint64_t fp;
1198 uint64_t lr;
1199 uint32_t tramp[2];
1200};
1201
1202static int target_setup_sigframe(struct target_rt_sigframe *sf,
1203 CPUARMState *env, target_sigset_t *set)
1204{
1205 int i;
1206 struct target_aux_context *aux =
1207 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1208
1209 /* set up the stack frame for unwinding */
1210 __put_user(env->xregs[29], &sf->fp);
1211 __put_user(env->xregs[30], &sf->lr);
1212
1213 for (i = 0; i < 31; i++) {
1214 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1215 }
1216 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1217 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001218 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001219
Peter Maydell7af03922014-05-01 18:36:17 +01001220 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001221
1222 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1223 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1224 }
1225
1226 for (i = 0; i < 32; i++) {
1227#ifdef TARGET_WORDS_BIGENDIAN
1228 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1229 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1230#else
1231 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1232 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1233#endif
1234 }
Will Newtone0ee1382014-01-04 22:15:48 +00001235 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1236 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001237 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1238 __put_user(sizeof(struct target_fpsimd_context),
1239 &aux->fpsimd.head.size);
1240
1241 /* set the "end" magic */
1242 __put_user(0, &aux->end.magic);
1243 __put_user(0, &aux->end.size);
1244
1245 return 0;
1246}
1247
1248static int target_restore_sigframe(CPUARMState *env,
1249 struct target_rt_sigframe *sf)
1250{
1251 sigset_t set;
1252 int i;
1253 struct target_aux_context *aux =
1254 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001255 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001256 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001257
1258 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001259 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001260
1261 for (i = 0; i < 31; i++) {
1262 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1263 }
1264
1265 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1266 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001267 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1268 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001269
1270 __get_user(magic, &aux->fpsimd.head.magic);
1271 __get_user(size, &aux->fpsimd.head.size);
1272
1273 if (magic != TARGET_FPSIMD_MAGIC
1274 || size != sizeof(struct target_fpsimd_context)) {
1275 return 1;
1276 }
1277
Peter Maydell4cf23482014-03-02 19:36:38 +00001278 for (i = 0; i < 32; i++) {
1279#ifdef TARGET_WORDS_BIGENDIAN
1280 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1281 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1282#else
1283 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1284 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1285#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001286 }
Will Newtone0ee1382014-01-04 22:15:48 +00001287 __get_user(fpsr, &aux->fpsimd.fpsr);
1288 vfp_set_fpsr(env, fpsr);
1289 __get_user(fpcr, &aux->fpsimd.fpcr);
1290 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001291
1292 return 0;
1293}
1294
1295static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1296{
1297 abi_ulong sp;
1298
1299 sp = env->xregs[31];
1300
1301 /*
1302 * This is the X/Open sanctioned signal stack switching.
1303 */
Riku Voipiob545f632014-07-15 17:01:55 +03001304 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001305 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1306 }
1307
1308 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1309
1310 return sp;
1311}
1312
1313static void target_setup_frame(int usig, struct target_sigaction *ka,
1314 target_siginfo_t *info, target_sigset_t *set,
1315 CPUARMState *env)
1316{
1317 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001318 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001319
1320 frame_addr = get_sigframe(ka, env);
1321 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1322 goto give_sigsegv;
1323 }
1324
1325 __put_user(0, &frame->uc.tuc_flags);
1326 __put_user(0, &frame->uc.tuc_link);
1327
1328 __put_user(target_sigaltstack_used.ss_sp,
1329 &frame->uc.tuc_stack.ss_sp);
1330 __put_user(sas_ss_flags(env->xregs[31]),
1331 &frame->uc.tuc_stack.ss_flags);
1332 __put_user(target_sigaltstack_used.ss_size,
1333 &frame->uc.tuc_stack.ss_size);
1334 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001335 if (ka->sa_flags & TARGET_SA_RESTORER) {
1336 return_addr = ka->sa_restorer;
1337 } else {
1338 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1339 __put_user(0xd2801168, &frame->tramp[0]);
1340 __put_user(0xd4000001, &frame->tramp[1]);
1341 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1342 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001343 env->xregs[0] = usig;
1344 env->xregs[31] = frame_addr;
1345 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1346 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001347 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001348 if (info) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00001349 tswap_siginfo(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001350 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1351 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1352 }
1353
1354 unlock_user_struct(frame, frame_addr, 1);
1355 return;
1356
1357 give_sigsegv:
1358 unlock_user_struct(frame, frame_addr, 1);
1359 force_sig(TARGET_SIGSEGV);
1360}
1361
1362static void setup_rt_frame(int sig, struct target_sigaction *ka,
1363 target_siginfo_t *info, target_sigset_t *set,
1364 CPUARMState *env)
1365{
1366 target_setup_frame(sig, ka, info, set, env);
1367}
1368
1369static void setup_frame(int sig, struct target_sigaction *ka,
1370 target_sigset_t *set, CPUARMState *env)
1371{
1372 target_setup_frame(sig, ka, 0, set, env);
1373}
1374
1375long do_rt_sigreturn(CPUARMState *env)
1376{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001377 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001378 abi_ulong frame_addr = env->xregs[31];
1379
1380 if (frame_addr & 15) {
1381 goto badframe;
1382 }
1383
1384 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1385 goto badframe;
1386 }
1387
1388 if (target_restore_sigframe(env, frame)) {
1389 goto badframe;
1390 }
1391
1392 if (do_sigaltstack(frame_addr +
1393 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1394 0, get_sp_from_cpustate(env)) == -EFAULT) {
1395 goto badframe;
1396 }
1397
1398 unlock_user_struct(frame, frame_addr, 0);
1399 return env->xregs[0];
1400
1401 badframe:
1402 unlock_user_struct(frame, frame_addr, 0);
1403 force_sig(TARGET_SIGSEGV);
1404 return 0;
1405}
1406
1407long do_sigreturn(CPUARMState *env)
1408{
1409 return do_rt_sigreturn(env);
1410}
1411
bellard43fff232003-07-09 19:31:39 +00001412#elif defined(TARGET_ARM)
1413
1414struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001415 abi_ulong trap_no;
1416 abi_ulong error_code;
1417 abi_ulong oldmask;
1418 abi_ulong arm_r0;
1419 abi_ulong arm_r1;
1420 abi_ulong arm_r2;
1421 abi_ulong arm_r3;
1422 abi_ulong arm_r4;
1423 abi_ulong arm_r5;
1424 abi_ulong arm_r6;
1425 abi_ulong arm_r7;
1426 abi_ulong arm_r8;
1427 abi_ulong arm_r9;
1428 abi_ulong arm_r10;
1429 abi_ulong arm_fp;
1430 abi_ulong arm_ip;
1431 abi_ulong arm_sp;
1432 abi_ulong arm_lr;
1433 abi_ulong arm_pc;
1434 abi_ulong arm_cpsr;
1435 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001436};
1437
pbrooka745ec62008-05-06 15:36:17 +00001438struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001439 abi_ulong tuc_flags;
1440 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001441 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001442 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001443 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001444};
1445
pbrooka745ec62008-05-06 15:36:17 +00001446struct target_ucontext_v2 {
1447 abi_ulong tuc_flags;
1448 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001449 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001450 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001451 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001452 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001453 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1454};
1455
Peter Maydell0d871bd2010-11-24 15:20:05 +00001456struct target_user_vfp {
1457 uint64_t fpregs[32];
1458 abi_ulong fpscr;
1459};
1460
1461struct target_user_vfp_exc {
1462 abi_ulong fpexc;
1463 abi_ulong fpinst;
1464 abi_ulong fpinst2;
1465};
1466
1467struct target_vfp_sigframe {
1468 abi_ulong magic;
1469 abi_ulong size;
1470 struct target_user_vfp ufp;
1471 struct target_user_vfp_exc ufp_exc;
1472} __attribute__((__aligned__(8)));
1473
Peter Maydell08e11252010-11-24 15:20:07 +00001474struct target_iwmmxt_sigframe {
1475 abi_ulong magic;
1476 abi_ulong size;
1477 uint64_t regs[16];
1478 /* Note that not all the coprocessor control registers are stored here */
1479 uint32_t wcssf;
1480 uint32_t wcasf;
1481 uint32_t wcgr0;
1482 uint32_t wcgr1;
1483 uint32_t wcgr2;
1484 uint32_t wcgr3;
1485} __attribute__((__aligned__(8)));
1486
Peter Maydell0d871bd2010-11-24 15:20:05 +00001487#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001488#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001489
pbrooka8c33202008-05-07 23:22:46 +00001490struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001491{
1492 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001493 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1494 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001495};
1496
pbrooka8c33202008-05-07 23:22:46 +00001497struct sigframe_v2
1498{
1499 struct target_ucontext_v2 uc;
1500 abi_ulong retcode;
1501};
1502
pbrooka745ec62008-05-06 15:36:17 +00001503struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001504{
bellardf8b0aa22007-11-11 23:03:42 +00001505 abi_ulong pinfo;
1506 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001507 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001508 struct target_ucontext_v1 uc;
1509 abi_ulong retcode;
1510};
1511
1512struct rt_sigframe_v2
1513{
1514 struct target_siginfo info;
1515 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001516 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001517};
1518
1519#define TARGET_CONFIG_CPU_32 1
1520
1521/*
1522 * For ARM syscalls, we encode the syscall number into the instruction.
1523 */
1524#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1525#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1526
1527/*
1528 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1529 * need two 16-bit instructions.
1530 */
1531#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1532#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1533
blueswir1992f48a2007-10-14 16:27:31 +00001534static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001535 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1536 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1537};
1538
1539
Andreas Färber05390242012-02-25 03:37:53 +01001540static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001541{
1542 return 1;
1543}
1544
pbrooka8c33202008-05-07 23:22:46 +00001545static void
bellard43fff232003-07-09 19:31:39 +00001546setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001547 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001548{
pbrooka8c33202008-05-07 23:22:46 +00001549 __put_user(env->regs[0], &sc->arm_r0);
1550 __put_user(env->regs[1], &sc->arm_r1);
1551 __put_user(env->regs[2], &sc->arm_r2);
1552 __put_user(env->regs[3], &sc->arm_r3);
1553 __put_user(env->regs[4], &sc->arm_r4);
1554 __put_user(env->regs[5], &sc->arm_r5);
1555 __put_user(env->regs[6], &sc->arm_r6);
1556 __put_user(env->regs[7], &sc->arm_r7);
1557 __put_user(env->regs[8], &sc->arm_r8);
1558 __put_user(env->regs[9], &sc->arm_r9);
1559 __put_user(env->regs[10], &sc->arm_r10);
1560 __put_user(env->regs[11], &sc->arm_fp);
1561 __put_user(env->regs[12], &sc->arm_ip);
1562 __put_user(env->regs[13], &sc->arm_sp);
1563 __put_user(env->regs[14], &sc->arm_lr);
1564 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001565#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001566 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001567#endif
1568
pbrooka8c33202008-05-07 23:22:46 +00001569 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1570 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1571 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1572 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001573}
1574
bellard579a97f2007-11-11 14:26:47 +00001575static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001576get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001577{
1578 unsigned long sp = regs->regs[13];
1579
bellard43fff232003-07-09 19:31:39 +00001580 /*
1581 * This is the X/Open sanctioned signal stack switching.
1582 */
pbrook624f7972008-05-31 16:11:38 +00001583 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001584 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001585 /*
1586 * ATPCS B01 mandates 8-byte alignment
1587 */
bellard579a97f2007-11-11 14:26:47 +00001588 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001589}
1590
Riku Voipio0188fad2014-04-23 13:34:15 +03001591static void
Andreas Färber05390242012-02-25 03:37:53 +01001592setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001593 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001594{
pbrook624f7972008-05-31 16:11:38 +00001595 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001596 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001597 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001598 uint32_t cpsr = cpsr_read(env);
1599
1600 cpsr &= ~CPSR_IT;
1601 if (thumb) {
1602 cpsr |= CPSR_T;
1603 } else {
1604 cpsr &= ~CPSR_T;
1605 }
bellard43fff232003-07-09 19:31:39 +00001606
pbrook624f7972008-05-31 16:11:38 +00001607 if (ka->sa_flags & TARGET_SA_RESTORER) {
1608 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001609 } else {
1610 unsigned int idx = thumb;
1611
pbrook624f7972008-05-31 16:11:38 +00001612 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001613 idx += 2;
1614
Riku Voipio0188fad2014-04-23 13:34:15 +03001615 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001616
bellardf8b0aa22007-11-11 23:03:42 +00001617 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001618 }
1619
1620 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001621 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001622 env->regs[14] = retcode;
1623 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001624 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001625}
1626
Andreas Färber05390242012-02-25 03:37:53 +01001627static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001628{
1629 int i;
1630 struct target_vfp_sigframe *vfpframe;
1631 vfpframe = (struct target_vfp_sigframe *)regspace;
1632 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1633 __put_user(sizeof(*vfpframe), &vfpframe->size);
1634 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001635 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001636 }
1637 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1638 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1639 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1640 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1641 return (abi_ulong*)(vfpframe+1);
1642}
1643
Andreas Färber05390242012-02-25 03:37:53 +01001644static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1645 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001646{
1647 int i;
1648 struct target_iwmmxt_sigframe *iwmmxtframe;
1649 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1650 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1651 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1652 for (i = 0; i < 16; i++) {
1653 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1654 }
1655 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1656 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1657 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1658 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1659 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1660 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1661 return (abi_ulong*)(iwmmxtframe+1);
1662}
1663
pbrooka8c33202008-05-07 23:22:46 +00001664static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001665 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001666{
pbrooka8c33202008-05-07 23:22:46 +00001667 struct target_sigaltstack stack;
1668 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001669 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001670
1671 /* Clear all the bits of the ucontext we don't use. */
1672 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1673
1674 memset(&stack, 0, sizeof(stack));
1675 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1676 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1677 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1678 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1679
1680 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001681 /* Save coprocessor signal frame. */
1682 regspace = uc->tuc_regspace;
1683 if (arm_feature(env, ARM_FEATURE_VFP)) {
1684 regspace = setup_sigframe_v2_vfp(regspace, env);
1685 }
Peter Maydell08e11252010-11-24 15:20:07 +00001686 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1687 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1688 }
1689
Peter Maydell0d871bd2010-11-24 15:20:05 +00001690 /* Write terminating magic word */
1691 __put_user(0, regspace);
1692
pbrooka8c33202008-05-07 23:22:46 +00001693 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1694 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1695 }
1696}
1697
1698/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001699static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001700 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001701{
1702 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001703 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001704 int i;
bellard43fff232003-07-09 19:31:39 +00001705
bellard579a97f2007-11-11 14:26:47 +00001706 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1707 return;
1708
pbrooka8c33202008-05-07 23:22:46 +00001709 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001710
Riku Voipio0188fad2014-04-23 13:34:15 +03001711 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1712 __put_user(set->sig[i], &frame->extramask[i - 1]);
1713 }
bellard43fff232003-07-09 19:31:39 +00001714
pbrooka8c33202008-05-07 23:22:46 +00001715 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1716 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001717
bellard579a97f2007-11-11 14:26:47 +00001718 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001719}
1720
pbrook624f7972008-05-31 16:11:38 +00001721static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001722 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001723{
1724 struct sigframe_v2 *frame;
1725 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1726
1727 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1728 return;
1729
1730 setup_sigframe_v2(&frame->uc, set, regs);
1731
1732 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1733 frame_addr + offsetof(struct sigframe_v2, retcode));
1734
1735 unlock_user_struct(frame, frame_addr, 1);
1736}
1737
pbrook624f7972008-05-31 16:11:38 +00001738static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001739 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001740{
1741 if (get_osversion() >= 0x020612) {
1742 setup_frame_v2(usig, ka, set, regs);
1743 } else {
1744 setup_frame_v1(usig, ka, set, regs);
1745 }
bellard43fff232003-07-09 19:31:39 +00001746}
1747
bellard579a97f2007-11-11 14:26:47 +00001748/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001749static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001750 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001751 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001752{
pbrooka745ec62008-05-06 15:36:17 +00001753 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001754 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001755 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001756 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001757 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001758
bellard579a97f2007-11-11 14:26:47 +00001759 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001760 return /* 1 */;
1761
pbrooka745ec62008-05-06 15:36:17 +00001762 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001763 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001764 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001765 __put_user(uc_addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001766 tswap_siginfo(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001767
1768 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001769 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001770
thsa04e1342007-09-27 13:57:58 +00001771 memset(&stack, 0, sizeof(stack));
1772 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1773 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1774 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001775 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001776
pbrooka8c33202008-05-07 23:22:46 +00001777 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001778 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03001779 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
bellard92319442004-06-19 16:58:13 +00001780 }
bellard43fff232003-07-09 19:31:39 +00001781
pbrooka8c33202008-05-07 23:22:46 +00001782 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1783 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001784
pbrooka8c33202008-05-07 23:22:46 +00001785 env->regs[1] = info_addr;
1786 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001787
pbrooka745ec62008-05-06 15:36:17 +00001788 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001789}
1790
pbrook624f7972008-05-31 16:11:38 +00001791static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001792 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001793 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001794{
1795 struct rt_sigframe_v2 *frame;
1796 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001797 abi_ulong info_addr, uc_addr;
1798
1799 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1800 return /* 1 */;
1801
1802 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1803 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001804 tswap_siginfo(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001805
pbrooka8c33202008-05-07 23:22:46 +00001806 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001807
pbrooka8c33202008-05-07 23:22:46 +00001808 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1809 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001810
pbrooka8c33202008-05-07 23:22:46 +00001811 env->regs[1] = info_addr;
1812 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001813
bellard579a97f2007-11-11 14:26:47 +00001814 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001815}
1816
pbrook624f7972008-05-31 16:11:38 +00001817static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001818 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001819 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001820{
1821 if (get_osversion() >= 0x020612) {
1822 setup_rt_frame_v2(usig, ka, info, set, env);
1823 } else {
1824 setup_rt_frame_v1(usig, ka, info, set, env);
1825 }
1826}
1827
bellard43fff232003-07-09 19:31:39 +00001828static int
Andreas Färber05390242012-02-25 03:37:53 +01001829restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001830{
1831 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001832 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001833
Riku Voipio1d8b5122014-04-23 10:26:05 +03001834 __get_user(env->regs[0], &sc->arm_r0);
1835 __get_user(env->regs[1], &sc->arm_r1);
1836 __get_user(env->regs[2], &sc->arm_r2);
1837 __get_user(env->regs[3], &sc->arm_r3);
1838 __get_user(env->regs[4], &sc->arm_r4);
1839 __get_user(env->regs[5], &sc->arm_r5);
1840 __get_user(env->regs[6], &sc->arm_r6);
1841 __get_user(env->regs[7], &sc->arm_r7);
1842 __get_user(env->regs[8], &sc->arm_r8);
1843 __get_user(env->regs[9], &sc->arm_r9);
1844 __get_user(env->regs[10], &sc->arm_r10);
1845 __get_user(env->regs[11], &sc->arm_fp);
1846 __get_user(env->regs[12], &sc->arm_ip);
1847 __get_user(env->regs[13], &sc->arm_sp);
1848 __get_user(env->regs[14], &sc->arm_lr);
1849 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001850#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001851 __get_user(cpsr, &sc->arm_cpsr);
pbrook75b680e2008-03-21 16:07:30 +00001852 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001853#endif
1854
1855 err |= !valid_user_regs(env);
1856
1857 return err;
1858}
1859
Andreas Färber05390242012-02-25 03:37:53 +01001860static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001861{
bellardf8b0aa22007-11-11 23:03:42 +00001862 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001863 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001864 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001865 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001866 int i;
bellard43fff232003-07-09 19:31:39 +00001867
1868 /*
1869 * Since we stacked the signal on a 64-bit boundary,
1870 * then 'sp' should be word aligned here. If it's
1871 * not, then the user is trying to mess with us.
1872 */
bellardf8b0aa22007-11-11 23:03:42 +00001873 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001874 if (frame_addr & 7) {
1875 goto badframe;
1876 }
1877
bellardf8b0aa22007-11-11 23:03:42 +00001878 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1879 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001880
Riku Voipiof5f601a2014-04-23 13:00:17 +03001881 __get_user(set.sig[0], &frame->sc.oldmask);
1882 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1883 __get_user(set.sig[i], &frame->extramask[i - 1]);
1884 }
bellard43fff232003-07-09 19:31:39 +00001885
bellard92319442004-06-19 16:58:13 +00001886 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001887 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001888
1889 if (restore_sigcontext(env, &frame->sc))
1890 goto badframe;
1891
1892#if 0
1893 /* Send SIGTRAP if we're single-stepping */
1894 if (ptrace_cancel_bpt(current))
1895 send_sig(SIGTRAP, current, 1);
1896#endif
bellardf8b0aa22007-11-11 23:03:42 +00001897 unlock_user_struct(frame, frame_addr, 0);
1898 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001899
1900badframe:
Riku Voipio66393fb2009-12-04 15:16:32 +02001901 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001902 return 0;
1903}
1904
Andreas Färber05390242012-02-25 03:37:53 +01001905static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001906{
1907 int i;
1908 abi_ulong magic, sz;
1909 uint32_t fpscr, fpexc;
1910 struct target_vfp_sigframe *vfpframe;
1911 vfpframe = (struct target_vfp_sigframe *)regspace;
1912
1913 __get_user(magic, &vfpframe->magic);
1914 __get_user(sz, &vfpframe->size);
1915 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1916 return 0;
1917 }
1918 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001919 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001920 }
1921 __get_user(fpscr, &vfpframe->ufp.fpscr);
1922 vfp_set_fpscr(env, fpscr);
1923 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1924 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1925 * and the exception flag is cleared
1926 */
1927 fpexc |= (1 << 30);
1928 fpexc &= ~((1 << 31) | (1 << 28));
1929 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1930 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1931 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1932 return (abi_ulong*)(vfpframe + 1);
1933}
1934
Andreas Färber05390242012-02-25 03:37:53 +01001935static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1936 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001937{
1938 int i;
1939 abi_ulong magic, sz;
1940 struct target_iwmmxt_sigframe *iwmmxtframe;
1941 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1942
1943 __get_user(magic, &iwmmxtframe->magic);
1944 __get_user(sz, &iwmmxtframe->size);
1945 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1946 return 0;
1947 }
1948 for (i = 0; i < 16; i++) {
1949 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1950 }
1951 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1952 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1953 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1954 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1955 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1956 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1957 return (abi_ulong*)(iwmmxtframe + 1);
1958}
1959
Andreas Färber05390242012-02-25 03:37:53 +01001960static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001961 struct target_ucontext_v2 *uc)
1962{
1963 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001964 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001965
1966 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001967 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001968
1969 if (restore_sigcontext(env, &uc->tuc_mcontext))
1970 return 1;
1971
Peter Maydell5f9099d2010-11-24 15:20:06 +00001972 /* Restore coprocessor signal frame */
1973 regspace = uc->tuc_regspace;
1974 if (arm_feature(env, ARM_FEATURE_VFP)) {
1975 regspace = restore_sigframe_v2_vfp(env, regspace);
1976 if (!regspace) {
1977 return 1;
1978 }
1979 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001980 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1981 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1982 if (!regspace) {
1983 return 1;
1984 }
1985 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001986
pbrooka8c33202008-05-07 23:22:46 +00001987 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1988 return 1;
1989
1990#if 0
1991 /* Send SIGTRAP if we're single-stepping */
1992 if (ptrace_cancel_bpt(current))
1993 send_sig(SIGTRAP, current, 1);
1994#endif
1995
1996 return 0;
1997}
1998
Andreas Färber05390242012-02-25 03:37:53 +01001999static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002000{
2001 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002002 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002003
2004 /*
2005 * Since we stacked the signal on a 64-bit boundary,
2006 * then 'sp' should be word aligned here. If it's
2007 * not, then the user is trying to mess with us.
2008 */
pbrooka8c33202008-05-07 23:22:46 +00002009 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002010 if (frame_addr & 7) {
2011 goto badframe;
2012 }
2013
pbrooka8c33202008-05-07 23:22:46 +00002014 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2015 goto badframe;
2016
2017 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2018 goto badframe;
2019
2020 unlock_user_struct(frame, frame_addr, 0);
2021 return env->regs[0];
2022
2023badframe:
2024 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002025 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002026 return 0;
2027}
2028
Andreas Färber05390242012-02-25 03:37:53 +01002029long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002030{
2031 if (get_osversion() >= 0x020612) {
2032 return do_sigreturn_v2(env);
2033 } else {
2034 return do_sigreturn_v1(env);
2035 }
2036}
2037
Andreas Färber05390242012-02-25 03:37:53 +01002038static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002039{
bellardf8b0aa22007-11-11 23:03:42 +00002040 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002041 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002042 sigset_t host_set;
2043
2044 /*
2045 * Since we stacked the signal on a 64-bit boundary,
2046 * then 'sp' should be word aligned here. If it's
2047 * not, then the user is trying to mess with us.
2048 */
bellardf8b0aa22007-11-11 23:03:42 +00002049 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002050 if (frame_addr & 7) {
2051 goto badframe;
2052 }
2053
bellardf8b0aa22007-11-11 23:03:42 +00002054 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2055 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002056
bellardb8076a72005-04-07 22:20:31 +00002057 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002058 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002059
bellardb8076a72005-04-07 22:20:31 +00002060 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002061 goto badframe;
2062
pbrooka745ec62008-05-06 15:36:17 +00002063 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 +00002064 goto badframe;
2065
bellard43fff232003-07-09 19:31:39 +00002066#if 0
2067 /* Send SIGTRAP if we're single-stepping */
2068 if (ptrace_cancel_bpt(current))
2069 send_sig(SIGTRAP, current, 1);
2070#endif
bellardf8b0aa22007-11-11 23:03:42 +00002071 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002072 return env->regs[0];
2073
2074badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002075 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002076 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002077 return 0;
2078}
2079
Andreas Färber05390242012-02-25 03:37:53 +01002080static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002081{
2082 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002083 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002084
2085 /*
2086 * Since we stacked the signal on a 64-bit boundary,
2087 * then 'sp' should be word aligned here. If it's
2088 * not, then the user is trying to mess with us.
2089 */
pbrooka745ec62008-05-06 15:36:17 +00002090 frame_addr = env->regs[13];
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);
bellard6d5e2162004-09-30 22:04:13 +00002286
bellard459a4012007-11-11 19:45:10 +00002287 sf = lock_user(VERIFY_WRITE, sf_addr,
2288 sizeof(struct target_signal_frame), 0);
2289 if (!sf)
2290 goto sigsegv;
2291
bellarde80cfcf2004-12-19 23:18:01 +00002292 //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
bellard6d5e2162004-09-30 22:04:13 +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:
bellarde80cfcf2004-12-19 23:18:01 +00002359 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002360 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002361 force_sig(TARGET_SIGSEGV);
2362}
bellard6d5e2162004-09-30 22:04:13 +00002363
pbrook624f7972008-05-31 16:11:38 +00002364static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002365 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002366 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002367{
2368 fprintf(stderr, "setup_rt_frame: not implemented\n");
2369}
2370
Andreas Färber05390242012-02-25 03:37:53 +01002371long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002372{
bellardf8b0aa22007-11-11 23:03:42 +00002373 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002374 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002375 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002376 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002377 sigset_t host_set;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002378 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002379
bellardf8b0aa22007-11-11 23:03:42 +00002380 sf_addr = env->regwptr[UREG_FP];
2381 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2382 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002383#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002384 fprintf(stderr, "sigreturn\n");
2385 fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
bellard80a9d032005-01-03 23:31:27 +00002386#endif
bellarde80cfcf2004-12-19 23:18:01 +00002387 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002388
2389 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002390
bellardf8b0aa22007-11-11 23:03:42 +00002391 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002392 goto segv_and_exit;
2393
Riku Voipio1d8b5122014-04-23 10:26:05 +03002394 __get_user(pc, &sf->info.si_regs.pc);
2395 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002396
bellard6d5e2162004-09-30 22:04:13 +00002397 if ((pc | npc) & 3)
2398 goto segv_and_exit;
2399
2400 /* 2. Restore the state */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002401 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002402
bellard6d5e2162004-09-30 22:04:13 +00002403 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002404 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2405 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2406
2407 env->pc = pc;
2408 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002409 __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002410 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002411 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
bellarde80cfcf2004-12-19 23:18:01 +00002412 }
bellarda315a142005-01-30 22:59:18 +00002413 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002414 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
bellarde80cfcf2004-12-19 23:18:01 +00002415 }
bellard6d5e2162004-09-30 22:04:13 +00002416
Peter Maydell2aec3a22011-06-16 17:37:14 +01002417 /* FIXME: implement FPU save/restore:
2418 * __get_user(fpu_save, &sf->fpu_save);
2419 * if (fpu_save)
2420 * err |= restore_fpu_state(env, fpu_save);
2421 */
bellard6d5e2162004-09-30 22:04:13 +00002422
2423 /* This is pretty much atomic, no amount locking would prevent
2424 * the races which exist anyways.
2425 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002426 __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002427 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002428 __get_user(set.sig[i], &sf->extramask[i - 1]);
bellarde80cfcf2004-12-19 23:18:01 +00002429 }
2430
2431 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002432 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002433
2434 if (err)
2435 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002436 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002437 return env->regwptr[0];
2438
2439segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002440 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002441 force_sig(TARGET_SIGSEGV);
2442}
2443
Andreas Färber05390242012-02-25 03:37:53 +01002444long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002445{
2446 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002447 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002448}
2449
bellard459a4012007-11-11 19:45:10 +00002450#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002451#define MC_TSTATE 0
2452#define MC_PC 1
2453#define MC_NPC 2
2454#define MC_Y 3
2455#define MC_G1 4
2456#define MC_G2 5
2457#define MC_G3 6
2458#define MC_G4 7
2459#define MC_G5 8
2460#define MC_G6 9
2461#define MC_G7 10
2462#define MC_O0 11
2463#define MC_O1 12
2464#define MC_O2 13
2465#define MC_O3 14
2466#define MC_O4 15
2467#define MC_O5 16
2468#define MC_O6 17
2469#define MC_O7 18
2470#define MC_NGREG 19
2471
Anthony Liguoric227f092009-10-01 16:12:16 -05002472typedef abi_ulong target_mc_greg_t;
2473typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002474
2475struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002476 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002477 uint32_t mcfq_insn;
2478};
2479
2480struct target_mc_fpu {
2481 union {
2482 uint32_t sregs[32];
2483 uint64_t dregs[32];
2484 //uint128_t qregs[16];
2485 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002486 abi_ulong mcfpu_fsr;
2487 abi_ulong mcfpu_fprs;
2488 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002489 struct target_mc_fq *mcfpu_fq;
2490 unsigned char mcfpu_qcnt;
2491 unsigned char mcfpu_qentsz;
2492 unsigned char mcfpu_enab;
2493};
Anthony Liguoric227f092009-10-01 16:12:16 -05002494typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002495
2496typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002497 target_mc_gregset_t mc_gregs;
2498 target_mc_greg_t mc_fp;
2499 target_mc_greg_t mc_i7;
2500 target_mc_fpu_t mc_fpregs;
2501} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002502
2503struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002504 struct target_ucontext *tuc_link;
2505 abi_ulong tuc_flags;
2506 target_sigset_t tuc_sigmask;
2507 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002508};
2509
2510/* A V9 register window */
2511struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002512 abi_ulong locals[8];
2513 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002514};
2515
2516#define TARGET_STACK_BIAS 2047
2517
2518/* {set, get}context() needed for 64-bit SparcLinux userland. */
2519void sparc64_set_context(CPUSPARCState *env)
2520{
bellard459a4012007-11-11 19:45:10 +00002521 abi_ulong ucp_addr;
2522 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002523 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002524 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002525 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002526 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002527
bellard459a4012007-11-11 19:45:10 +00002528 ucp_addr = env->regwptr[UREG_I0];
2529 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2530 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002531 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002532 __get_user(pc, &((*grp)[MC_PC]));
2533 __get_user(npc, &((*grp)[MC_NPC]));
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002534 if ((pc | npc) & 3)
blueswir15bfb56b2007-10-05 17:01:51 +00002535 goto do_sigsegv;
2536 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002537 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002538 sigset_t set;
2539
2540 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002541 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002542 } else {
bellard459a4012007-11-11 19:45:10 +00002543 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002544 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002545 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002546 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002547 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002548 }
blueswir15bfb56b2007-10-05 17:01:51 +00002549 }
2550 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002551 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002552 }
2553 env->pc = pc;
2554 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002555 __get_user(env->y, &((*grp)[MC_Y]));
2556 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002557 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002558 cpu_put_ccr(env, tstate >> 32);
2559 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002560 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2561 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2562 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2563 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2564 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2565 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2566 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2567 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2568 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2569 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2570 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2571 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2572 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2573 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2574 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002575
Riku Voipio1d8b5122014-04-23 10:26:05 +03002576 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2577 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002578
bellard459a4012007-11-11 19:45:10 +00002579 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2580 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2581 abi_ulong) != 0)
2582 goto do_sigsegv;
2583 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2584 abi_ulong) != 0)
2585 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002586 /* FIXME this does not match how the kernel handles the FPU in
2587 * its sparc64_set_context implementation. In particular the FPU
2588 * is only restored if fenab is non-zero in:
2589 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2590 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002591 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002592 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002593 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2594 for (i = 0; i < 64; i++, src++) {
2595 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002596 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002597 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002598 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002599 }
2600 }
bellard459a4012007-11-11 19:45:10 +00002601 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002602 __get_user(env->fsr,
2603 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2604 __get_user(env->gsr,
2605 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002606 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002607 return;
2608 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002609 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002610 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002611}
2612
2613void sparc64_get_context(CPUSPARCState *env)
2614{
bellard459a4012007-11-11 19:45:10 +00002615 abi_ulong ucp_addr;
2616 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002617 target_mc_gregset_t *grp;
2618 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002619 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002620 int err;
2621 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002622 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002623 sigset_t set;
2624
bellard459a4012007-11-11 19:45:10 +00002625 ucp_addr = env->regwptr[UREG_I0];
2626 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2627 goto do_sigsegv;
2628
Aurelien Jarno60e99242010-03-29 02:12:51 +02002629 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002630 grp = &mcp->mc_gregs;
2631
2632 /* Skip over the trap instruction, first. */
2633 env->pc = env->npc;
2634 env->npc += 4;
2635
2636 err = 0;
2637
Alex Barcelo1c275922014-03-14 14:36:55 +00002638 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002639 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002640 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002641 __put_user(target_set.sig[0],
2642 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002643 } else {
2644 abi_ulong *src, *dst;
2645 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002646 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002647 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002648 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002649 }
blueswir15bfb56b2007-10-05 17:01:51 +00002650 if (err)
2651 goto do_sigsegv;
2652 }
2653
bellard459a4012007-11-11 19:45:10 +00002654 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002655 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2656 __put_user(env->pc, &((*grp)[MC_PC]));
2657 __put_user(env->npc, &((*grp)[MC_NPC]));
2658 __put_user(env->y, &((*grp)[MC_Y]));
2659 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2660 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2661 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2662 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2663 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2664 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2665 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2666 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2667 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2668 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2669 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2670 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2671 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2672 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2673 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002674
bellard459a4012007-11-11 19:45:10 +00002675 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2676 fp = i7 = 0;
2677 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2678 abi_ulong) != 0)
2679 goto do_sigsegv;
2680 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2681 abi_ulong) != 0)
2682 goto do_sigsegv;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002683 __put_user(fp, &(mcp->mc_fp));
2684 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002685
bellard459a4012007-11-11 19:45:10 +00002686 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002687 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2688 for (i = 0; i < 64; i++, dst++) {
2689 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002690 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002691 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002692 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002693 }
2694 }
bellard459a4012007-11-11 19:45:10 +00002695 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002696 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2697 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2698 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002699
2700 if (err)
2701 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002702 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002703 return;
2704 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002705 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002706 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002707}
2708#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002709#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002710
Richard Hendersonff970902013-02-10 10:30:42 -08002711# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002712struct target_sigcontext {
2713 uint32_t sc_regmask; /* Unused */
2714 uint32_t sc_status;
2715 uint64_t sc_pc;
2716 uint64_t sc_regs[32];
2717 uint64_t sc_fpregs[32];
2718 uint32_t sc_ownedfp; /* Unused */
2719 uint32_t sc_fpc_csr;
2720 uint32_t sc_fpc_eir; /* Unused */
2721 uint32_t sc_used_math;
2722 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002723 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002724 uint64_t sc_mdhi;
2725 uint64_t sc_mdlo;
2726 target_ulong sc_hi1; /* Was sc_cause */
2727 target_ulong sc_lo1; /* Was sc_badvaddr */
2728 target_ulong sc_hi2; /* Was sc_sigset[4] */
2729 target_ulong sc_lo2;
2730 target_ulong sc_hi3;
2731 target_ulong sc_lo3;
2732};
Richard Hendersonff970902013-02-10 10:30:42 -08002733# else /* N32 || N64 */
2734struct target_sigcontext {
2735 uint64_t sc_regs[32];
2736 uint64_t sc_fpregs[32];
2737 uint64_t sc_mdhi;
2738 uint64_t sc_hi1;
2739 uint64_t sc_hi2;
2740 uint64_t sc_hi3;
2741 uint64_t sc_mdlo;
2742 uint64_t sc_lo1;
2743 uint64_t sc_lo2;
2744 uint64_t sc_lo3;
2745 uint64_t sc_pc;
2746 uint32_t sc_fpc_csr;
2747 uint32_t sc_used_math;
2748 uint32_t sc_dsp;
2749 uint32_t sc_reserved;
2750};
2751# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002752
2753struct sigframe {
2754 uint32_t sf_ass[4]; /* argument save space for o32 */
2755 uint32_t sf_code[2]; /* signal trampoline */
2756 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002757 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002758};
2759
pbrook0b1bcb02009-04-21 01:41:10 +00002760struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002761 target_ulong tuc_flags;
2762 target_ulong tuc_link;
2763 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002764 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002765 struct target_sigcontext tuc_mcontext;
2766 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002767};
2768
2769struct target_rt_sigframe {
2770 uint32_t rs_ass[4]; /* argument save space for o32 */
2771 uint32_t rs_code[2]; /* signal trampoline */
2772 struct target_siginfo rs_info;
2773 struct target_ucontext rs_uc;
2774};
2775
bellard106ec872006-06-27 21:08:10 +00002776/* Install trampoline to jump back from signal handler */
2777static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2778{
Richard Henderson084d0492013-02-10 10:30:44 -08002779 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002780
2781 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002782 * Set up the return code ...
2783 *
2784 * li v0, __NR__foo_sigreturn
2785 * syscall
2786 */
bellard106ec872006-06-27 21:08:10 +00002787
Riku Voipio1d8b5122014-04-23 10:26:05 +03002788 __put_user(0x24020000 + syscall, tramp + 0);
2789 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002790 return err;
2791}
2792
Riku Voipio41ecc722014-04-23 11:01:00 +03002793static inline void setup_sigcontext(CPUMIPSState *regs,
2794 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002795{
Richard Henderson084d0492013-02-10 10:30:44 -08002796 int i;
bellard106ec872006-06-27 21:08:10 +00002797
Riku Voipio1d8b5122014-04-23 10:26:05 +03002798 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002799 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002800
Richard Henderson084d0492013-02-10 10:30:44 -08002801 __put_user(0, &sc->sc_regs[0]);
2802 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002803 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002804 }
bellard106ec872006-06-27 21:08:10 +00002805
Riku Voipio1d8b5122014-04-23 10:26:05 +03002806 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2807 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002808
Richard Henderson084d0492013-02-10 10:30:44 -08002809 /* Rather than checking for dsp existence, always copy. The storage
2810 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002811 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2812 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2813 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2814 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2815 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2816 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002817 {
2818 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002819 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002820 }
Richard Henderson084d0492013-02-10 10:30:44 -08002821
Riku Voipio1d8b5122014-04-23 10:26:05 +03002822 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002823
2824 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002825 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002826 }
bellard106ec872006-06-27 21:08:10 +00002827}
2828
Riku Voipio016d2e12014-04-23 11:19:48 +03002829static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002830restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002831{
Richard Henderson084d0492013-02-10 10:30:44 -08002832 int i;
bellard106ec872006-06-27 21:08:10 +00002833
Riku Voipio1d8b5122014-04-23 10:26:05 +03002834 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002835
Riku Voipio1d8b5122014-04-23 10:26:05 +03002836 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2837 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002838
Richard Henderson084d0492013-02-10 10:30:44 -08002839 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002840 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002841 }
2842
Riku Voipio1d8b5122014-04-23 10:26:05 +03002843 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2844 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2845 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2846 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2847 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2848 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002849 {
2850 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002851 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002852 cpu_wrdsp(dsp, 0x3ff, regs);
2853 }
2854
2855 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002856 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002857 }
bellard106ec872006-06-27 21:08:10 +00002858}
Richard Hendersonff970902013-02-10 10:30:42 -08002859
bellard106ec872006-06-27 21:08:10 +00002860/*
2861 * Determine which stack to use..
2862 */
bellard579a97f2007-11-11 14:26:47 +00002863static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002864get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002865{
2866 unsigned long sp;
2867
2868 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002869 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002870
2871 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002872 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002873 * above the user stack, 16-bytes before the next lowest
2874 * 16 byte boundary. Try to avoid trashing it.
2875 */
2876 sp -= 32;
2877
bellard106ec872006-06-27 21:08:10 +00002878 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002879 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002880 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2881 }
bellard106ec872006-06-27 21:08:10 +00002882
bellard579a97f2007-11-11 14:26:47 +00002883 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002884}
2885
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002886static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2887{
2888 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2889 env->hflags &= ~MIPS_HFLAG_M16;
2890 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2891 env->active_tc.PC &= ~(target_ulong) 1;
2892 }
2893}
2894
Richard Hendersonff970902013-02-10 10:30:42 -08002895# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002896/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002897static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002898 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002899{
2900 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002901 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002902 int i;
2903
bellard579a97f2007-11-11 14:26:47 +00002904 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2905 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002906 goto give_sigsegv;
2907
2908 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2909
Riku Voipio41ecc722014-04-23 11:01:00 +03002910 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002911
2912 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03002913 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00002914 }
2915
2916 /*
2917 * Arguments to signal handler:
2918 *
2919 * a0 = signal number
2920 * a1 = 0 (should be cause)
2921 * a2 = pointer to struct sigcontext
2922 *
2923 * $25 and PC point to the signal handler, $29 points to the
2924 * struct sigframe.
2925 */
thsb5dc7732008-06-27 10:02:35 +00002926 regs->active_tc.gpr[ 4] = sig;
2927 regs->active_tc.gpr[ 5] = 0;
2928 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2929 regs->active_tc.gpr[29] = frame_addr;
2930 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002931 /* The original kernel code sets CP0_EPC to the handler
2932 * since it returns to userland using eret
2933 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002934 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002935 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002936 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002937 return;
2938
2939give_sigsegv:
2940 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002941}
2942
Andreas Färber05390242012-02-25 03:37:53 +01002943long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002944{
ths388bb212007-05-13 13:58:00 +00002945 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002946 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002947 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002948 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002949 int i;
bellard106ec872006-06-27 21:08:10 +00002950
2951#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002952 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002953#endif
thsb5dc7732008-06-27 10:02:35 +00002954 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002955 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002956 goto badframe;
2957
ths388bb212007-05-13 13:58:00 +00002958 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03002959 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00002960 }
bellard106ec872006-06-27 21:08:10 +00002961
ths388bb212007-05-13 13:58:00 +00002962 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002963 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002964
Riku Voipio016d2e12014-04-23 11:19:48 +03002965 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002966
2967#if 0
ths388bb212007-05-13 13:58:00 +00002968 /*
2969 * Don't let your children do this ...
2970 */
2971 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002972 "move\t$29, %0\n\t"
2973 "j\tsyscall_exit"
2974 :/* no outputs */
2975 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002976 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002977#endif
ths3b46e622007-09-17 08:09:54 +00002978
thsb5dc7732008-06-27 10:02:35 +00002979 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002980 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00002981 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002982 * maybe a problem with nested signals ? */
2983 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00002984 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00002985
2986badframe:
ths388bb212007-05-13 13:58:00 +00002987 force_sig(TARGET_SIGSEGV/*, current*/);
2988 return 0;
bellard106ec872006-06-27 21:08:10 +00002989}
Richard Hendersonff970902013-02-10 10:30:42 -08002990# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002991
pbrook624f7972008-05-31 16:11:38 +00002992static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002993 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002994 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00002995{
pbrook0b1bcb02009-04-21 01:41:10 +00002996 struct target_rt_sigframe *frame;
2997 abi_ulong frame_addr;
2998 int i;
2999
3000 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3001 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3002 goto give_sigsegv;
3003
3004 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3005
Peter Maydellf6c7a052015-01-08 12:19:48 +00003006 tswap_siginfo(&frame->rs_info, info);
pbrook0b1bcb02009-04-21 01:41:10 +00003007
Aurelien Jarno60e99242010-03-29 02:12:51 +02003008 __put_user(0, &frame->rs_uc.tuc_flags);
3009 __put_user(0, &frame->rs_uc.tuc_link);
3010 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3011 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003012 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003013 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003014
Aurelien Jarno60e99242010-03-29 02:12:51 +02003015 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003016
3017 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003018 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003019 }
3020
3021 /*
3022 * Arguments to signal handler:
3023 *
3024 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003025 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003026 * a2 = pointer to struct ucontext
3027 *
3028 * $25 and PC point to the signal handler, $29 points to the
3029 * struct sigframe.
3030 */
3031 env->active_tc.gpr[ 4] = sig;
3032 env->active_tc.gpr[ 5] = frame_addr
3033 + offsetof(struct target_rt_sigframe, rs_info);
3034 env->active_tc.gpr[ 6] = frame_addr
3035 + offsetof(struct target_rt_sigframe, rs_uc);
3036 env->active_tc.gpr[29] = frame_addr;
3037 env->active_tc.gpr[31] = frame_addr
3038 + offsetof(struct target_rt_sigframe, rs_code);
3039 /* The original kernel code sets CP0_EPC to the handler
3040 * since it returns to userland using eret
3041 * we cannot do this here, and we must set PC directly */
3042 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003043 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003044 unlock_user_struct(frame, frame_addr, 1);
3045 return;
3046
3047give_sigsegv:
3048 unlock_user_struct(frame, frame_addr, 1);
3049 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003050}
3051
Andreas Färber05390242012-02-25 03:37:53 +01003052long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003053{
pbrook0b1bcb02009-04-21 01:41:10 +00003054 struct target_rt_sigframe *frame;
3055 abi_ulong frame_addr;
3056 sigset_t blocked;
3057
3058#if defined(DEBUG_SIGNAL)
3059 fprintf(stderr, "do_rt_sigreturn\n");
3060#endif
3061 frame_addr = env->active_tc.gpr[29];
3062 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3063 goto badframe;
3064
Aurelien Jarno60e99242010-03-29 02:12:51 +02003065 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003066 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003067
Riku Voipio016d2e12014-04-23 11:19:48 +03003068 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003069
3070 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003071 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003072 0, get_sp_from_cpustate(env)) == -EFAULT)
3073 goto badframe;
3074
3075 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003076 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003077 /* I am not sure this is right, but it seems to work
3078 * maybe a problem with nested signals ? */
3079 env->CP0_EPC = 0;
3080 return -TARGET_QEMU_ESIGRETURN;
3081
3082badframe:
3083 force_sig(TARGET_SIGSEGV/*, current*/);
3084 return 0;
bellard106ec872006-06-27 21:08:10 +00003085}
bellard6d5e2162004-09-30 22:04:13 +00003086
thsc3b5bc82007-12-02 06:31:25 +00003087#elif defined(TARGET_SH4)
3088
3089/*
3090 * code and data structures from linux kernel:
3091 * include/asm-sh/sigcontext.h
3092 * arch/sh/kernel/signal.c
3093 */
3094
3095struct target_sigcontext {
3096 target_ulong oldmask;
3097
3098 /* CPU registers */
3099 target_ulong sc_gregs[16];
3100 target_ulong sc_pc;
3101 target_ulong sc_pr;
3102 target_ulong sc_sr;
3103 target_ulong sc_gbr;
3104 target_ulong sc_mach;
3105 target_ulong sc_macl;
3106
3107 /* FPU registers */
3108 target_ulong sc_fpregs[16];
3109 target_ulong sc_xfpregs[16];
3110 unsigned int sc_fpscr;
3111 unsigned int sc_fpul;
3112 unsigned int sc_ownedfp;
3113};
3114
3115struct target_sigframe
3116{
3117 struct target_sigcontext sc;
3118 target_ulong extramask[TARGET_NSIG_WORDS-1];
3119 uint16_t retcode[3];
3120};
3121
3122
3123struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003124 target_ulong tuc_flags;
3125 struct target_ucontext *tuc_link;
3126 target_stack_t tuc_stack;
3127 struct target_sigcontext tuc_mcontext;
3128 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003129};
3130
3131struct target_rt_sigframe
3132{
3133 struct target_siginfo info;
3134 struct target_ucontext uc;
3135 uint16_t retcode[3];
3136};
3137
3138
3139#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3140#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3141
pbrook624f7972008-05-31 16:11:38 +00003142static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003143 unsigned long sp, size_t frame_size)
3144{
pbrook624f7972008-05-31 16:11:38 +00003145 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003146 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3147 }
3148
3149 return (sp - frame_size) & -8ul;
3150}
3151
Riku Voipio41ecc722014-04-23 11:01:00 +03003152static void setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003153 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003154{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003155 int i;
thsc3b5bc82007-12-02 06:31:25 +00003156
Riku Voipio1d8b5122014-04-23 10:26:05 +03003157#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003158 COPY(gregs[0]); COPY(gregs[1]);
3159 COPY(gregs[2]); COPY(gregs[3]);
3160 COPY(gregs[4]); COPY(gregs[5]);
3161 COPY(gregs[6]); COPY(gregs[7]);
3162 COPY(gregs[8]); COPY(gregs[9]);
3163 COPY(gregs[10]); COPY(gregs[11]);
3164 COPY(gregs[12]); COPY(gregs[13]);
3165 COPY(gregs[14]); COPY(gregs[15]);
3166 COPY(gbr); COPY(mach);
3167 COPY(macl); COPY(pr);
3168 COPY(sr); COPY(pc);
3169#undef COPY
3170
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003171 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003172 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003173 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003174 __put_user(regs->fpscr, &sc->sc_fpscr);
3175 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003176
3177 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003178 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003179}
3180
Riku Voipio016d2e12014-04-23 11:19:48 +03003181static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003182 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003183{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003184 int i;
thsc3b5bc82007-12-02 06:31:25 +00003185
Riku Voipio1d8b5122014-04-23 10:26:05 +03003186#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003187 COPY(gregs[1]);
3188 COPY(gregs[2]); COPY(gregs[3]);
3189 COPY(gregs[4]); COPY(gregs[5]);
3190 COPY(gregs[6]); COPY(gregs[7]);
3191 COPY(gregs[8]); COPY(gregs[9]);
3192 COPY(gregs[10]); COPY(gregs[11]);
3193 COPY(gregs[12]); COPY(gregs[13]);
3194 COPY(gregs[14]); COPY(gregs[15]);
3195 COPY(gbr); COPY(mach);
3196 COPY(macl); COPY(pr);
3197 COPY(sr); COPY(pc);
3198#undef COPY
3199
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003200 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003201 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003202 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003203 __get_user(regs->fpscr, &sc->sc_fpscr);
3204 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003205
3206 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003207 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003208}
3209
pbrook624f7972008-05-31 16:11:38 +00003210static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003211 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003212{
3213 struct target_sigframe *frame;
3214 abi_ulong frame_addr;
3215 int i;
3216 int err = 0;
thsc3b5bc82007-12-02 06:31:25 +00003217
3218 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3219 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3220 goto give_sigsegv;
3221
Riku Voipio41ecc722014-04-23 11:01:00 +03003222 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003223
3224 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003225 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003226 }
3227
3228 /* Set up to return from userspace. If provided, use a stub
3229 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003230 if (ka->sa_flags & TARGET_SA_RESTORER) {
3231 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003232 } else {
3233 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003234 __put_user(MOVW(2), &frame->retcode[0]);
3235 __put_user(TRAP_NOARG, &frame->retcode[1]);
3236 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003237 regs->pr = (unsigned long) frame->retcode;
3238 }
3239
3240 if (err)
3241 goto give_sigsegv;
3242
3243 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003244 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003245 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003246 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003247 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003248 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003249
3250 unlock_user_struct(frame, frame_addr, 1);
3251 return;
3252
3253give_sigsegv:
3254 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003255 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003256}
3257
pbrook624f7972008-05-31 16:11:38 +00003258static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003259 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003260 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003261{
3262 struct target_rt_sigframe *frame;
3263 abi_ulong frame_addr;
3264 int i;
3265 int err = 0;
thsc3b5bc82007-12-02 06:31:25 +00003266
3267 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3268 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3269 goto give_sigsegv;
3270
Peter Maydellf6c7a052015-01-08 12:19:48 +00003271 tswap_siginfo(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003272
3273 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003274 __put_user(0, &frame->uc.tuc_flags);
3275 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3276 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3277 &frame->uc.tuc_stack.ss_sp);
3278 __put_user(sas_ss_flags(regs->gregs[15]),
3279 &frame->uc.tuc_stack.ss_flags);
3280 __put_user(target_sigaltstack_used.ss_size,
3281 &frame->uc.tuc_stack.ss_size);
3282 setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003283 regs, set->sig[0]);
3284 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003285 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003286 }
3287
3288 /* Set up to return from userspace. If provided, use a stub
3289 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003290 if (ka->sa_flags & TARGET_SA_RESTORER) {
3291 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003292 } else {
3293 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003294 __put_user(MOVW(2), &frame->retcode[0]);
3295 __put_user(TRAP_NOARG, &frame->retcode[1]);
3296 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003297 regs->pr = (unsigned long) frame->retcode;
3298 }
3299
3300 if (err)
3301 goto give_sigsegv;
3302
3303 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003304 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003305 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003306 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3307 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003308 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003309
3310 unlock_user_struct(frame, frame_addr, 1);
3311 return;
3312
3313give_sigsegv:
3314 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003315 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003316}
3317
Andreas Färber05390242012-02-25 03:37:53 +01003318long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003319{
3320 struct target_sigframe *frame;
3321 abi_ulong frame_addr;
3322 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003323 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003324 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003325 int i;
3326 int err = 0;
3327
3328#if defined(DEBUG_SIGNAL)
3329 fprintf(stderr, "do_sigreturn\n");
3330#endif
3331 frame_addr = regs->gregs[15];
3332 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3333 goto badframe;
3334
Riku Voipio1d8b5122014-04-23 10:26:05 +03003335 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003336 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003337 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003338 }
3339
3340 if (err)
3341 goto badframe;
3342
3343 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003344 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003345
Riku Voipio016d2e12014-04-23 11:19:48 +03003346 restore_sigcontext(regs, &frame->sc, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003347
3348 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003349 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003350
3351badframe:
3352 unlock_user_struct(frame, frame_addr, 0);
3353 force_sig(TARGET_SIGSEGV);
3354 return 0;
3355}
3356
Andreas Färber05390242012-02-25 03:37:53 +01003357long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003358{
3359 struct target_rt_sigframe *frame;
3360 abi_ulong frame_addr;
3361 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003362 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003363
3364#if defined(DEBUG_SIGNAL)
3365 fprintf(stderr, "do_rt_sigreturn\n");
3366#endif
3367 frame_addr = regs->gregs[15];
3368 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3369 goto badframe;
3370
Aurelien Jarno60e99242010-03-29 02:12:51 +02003371 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003372 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003373
Riku Voipio016d2e12014-04-23 11:19:48 +03003374 restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003375
3376 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003377 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003378 0, get_sp_from_cpustate(regs)) == -EFAULT)
3379 goto badframe;
3380
3381 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003382 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003383
3384badframe:
3385 unlock_user_struct(frame, frame_addr, 0);
3386 force_sig(TARGET_SIGSEGV);
3387 return 0;
3388}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003389#elif defined(TARGET_MICROBLAZE)
3390
3391struct target_sigcontext {
3392 struct target_pt_regs regs; /* needs to be first */
3393 uint32_t oldmask;
3394};
3395
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003396struct target_stack_t {
3397 abi_ulong ss_sp;
3398 int ss_flags;
3399 unsigned int ss_size;
3400};
3401
3402struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003403 abi_ulong tuc_flags;
3404 abi_ulong tuc_link;
3405 struct target_stack_t tuc_stack;
3406 struct target_sigcontext tuc_mcontext;
3407 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003408};
3409
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003410/* Signal frames. */
3411struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003412 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003413 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3414 uint32_t tramp[2];
3415};
3416
3417struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003418 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003419 struct ucontext uc;
3420 uint32_t tramp[2];
3421};
3422
Andreas Färber05390242012-02-25 03:37:53 +01003423static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003424{
3425 __put_user(env->regs[0], &sc->regs.r0);
3426 __put_user(env->regs[1], &sc->regs.r1);
3427 __put_user(env->regs[2], &sc->regs.r2);
3428 __put_user(env->regs[3], &sc->regs.r3);
3429 __put_user(env->regs[4], &sc->regs.r4);
3430 __put_user(env->regs[5], &sc->regs.r5);
3431 __put_user(env->regs[6], &sc->regs.r6);
3432 __put_user(env->regs[7], &sc->regs.r7);
3433 __put_user(env->regs[8], &sc->regs.r8);
3434 __put_user(env->regs[9], &sc->regs.r9);
3435 __put_user(env->regs[10], &sc->regs.r10);
3436 __put_user(env->regs[11], &sc->regs.r11);
3437 __put_user(env->regs[12], &sc->regs.r12);
3438 __put_user(env->regs[13], &sc->regs.r13);
3439 __put_user(env->regs[14], &sc->regs.r14);
3440 __put_user(env->regs[15], &sc->regs.r15);
3441 __put_user(env->regs[16], &sc->regs.r16);
3442 __put_user(env->regs[17], &sc->regs.r17);
3443 __put_user(env->regs[18], &sc->regs.r18);
3444 __put_user(env->regs[19], &sc->regs.r19);
3445 __put_user(env->regs[20], &sc->regs.r20);
3446 __put_user(env->regs[21], &sc->regs.r21);
3447 __put_user(env->regs[22], &sc->regs.r22);
3448 __put_user(env->regs[23], &sc->regs.r23);
3449 __put_user(env->regs[24], &sc->regs.r24);
3450 __put_user(env->regs[25], &sc->regs.r25);
3451 __put_user(env->regs[26], &sc->regs.r26);
3452 __put_user(env->regs[27], &sc->regs.r27);
3453 __put_user(env->regs[28], &sc->regs.r28);
3454 __put_user(env->regs[29], &sc->regs.r29);
3455 __put_user(env->regs[30], &sc->regs.r30);
3456 __put_user(env->regs[31], &sc->regs.r31);
3457 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3458}
3459
Andreas Färber05390242012-02-25 03:37:53 +01003460static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003461{
3462 __get_user(env->regs[0], &sc->regs.r0);
3463 __get_user(env->regs[1], &sc->regs.r1);
3464 __get_user(env->regs[2], &sc->regs.r2);
3465 __get_user(env->regs[3], &sc->regs.r3);
3466 __get_user(env->regs[4], &sc->regs.r4);
3467 __get_user(env->regs[5], &sc->regs.r5);
3468 __get_user(env->regs[6], &sc->regs.r6);
3469 __get_user(env->regs[7], &sc->regs.r7);
3470 __get_user(env->regs[8], &sc->regs.r8);
3471 __get_user(env->regs[9], &sc->regs.r9);
3472 __get_user(env->regs[10], &sc->regs.r10);
3473 __get_user(env->regs[11], &sc->regs.r11);
3474 __get_user(env->regs[12], &sc->regs.r12);
3475 __get_user(env->regs[13], &sc->regs.r13);
3476 __get_user(env->regs[14], &sc->regs.r14);
3477 __get_user(env->regs[15], &sc->regs.r15);
3478 __get_user(env->regs[16], &sc->regs.r16);
3479 __get_user(env->regs[17], &sc->regs.r17);
3480 __get_user(env->regs[18], &sc->regs.r18);
3481 __get_user(env->regs[19], &sc->regs.r19);
3482 __get_user(env->regs[20], &sc->regs.r20);
3483 __get_user(env->regs[21], &sc->regs.r21);
3484 __get_user(env->regs[22], &sc->regs.r22);
3485 __get_user(env->regs[23], &sc->regs.r23);
3486 __get_user(env->regs[24], &sc->regs.r24);
3487 __get_user(env->regs[25], &sc->regs.r25);
3488 __get_user(env->regs[26], &sc->regs.r26);
3489 __get_user(env->regs[27], &sc->regs.r27);
3490 __get_user(env->regs[28], &sc->regs.r28);
3491 __get_user(env->regs[29], &sc->regs.r29);
3492 __get_user(env->regs[30], &sc->regs.r30);
3493 __get_user(env->regs[31], &sc->regs.r31);
3494 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3495}
3496
3497static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003498 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003499{
3500 abi_ulong sp = env->regs[1];
3501
Riku Voipiob545f632014-07-15 17:01:55 +03003502 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003503 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003504 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003505
3506 return ((sp - frame_size) & -8UL);
3507}
3508
3509static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003510 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003511{
3512 struct target_signal_frame *frame;
3513 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003514 int i;
3515
3516 frame_addr = get_sigframe(ka, env, sizeof *frame);
3517 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3518 goto badframe;
3519
3520 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003521 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003522
3523 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003524 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003525 }
3526
Richard Hendersonf711df62010-11-22 14:57:52 -08003527 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003528
3529 /* Set up to return from userspace. If provided, use a stub
3530 already in userspace. */
3531 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3532 if (ka->sa_flags & TARGET_SA_RESTORER) {
3533 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3534 } else {
3535 uint32_t t;
3536 /* Note, these encodings are _big endian_! */
3537 /* addi r12, r0, __NR_sigreturn */
3538 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003539 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003540 /* brki r14, 0x8 */
3541 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003542 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003543
3544 /* Return from sighandler will jump to the tramp.
3545 Negative 8 offset because return is rtsd r15, 8 */
3546 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3547 }
3548
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003549 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003550 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003551 /* Signal handler args: */
3552 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003553 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003554 /* arg 1: sigcontext */
3555 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003556
3557 /* Offset of 4 to handle microblaze rtid r14, 0 */
3558 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3559
3560 unlock_user_struct(frame, frame_addr, 1);
3561 return;
3562 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003563 force_sig(TARGET_SIGSEGV);
3564}
3565
3566static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003567 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003568 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003569{
3570 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3571}
3572
Andreas Färber05390242012-02-25 03:37:53 +01003573long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003574{
3575 struct target_signal_frame *frame;
3576 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003577 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003578 sigset_t set;
3579 int i;
3580
3581 frame_addr = env->regs[R_SP];
3582 /* Make sure the guest isn't playing games. */
3583 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3584 goto badframe;
3585
3586 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003587 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003588 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003589 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003590 }
3591 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003592 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003593
Richard Hendersonf711df62010-11-22 14:57:52 -08003594 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003595 /* We got here through a sigreturn syscall, our path back is via an
3596 rtb insn so setup r14 for that. */
3597 env->regs[14] = env->sregs[SR_PC];
3598
3599 unlock_user_struct(frame, frame_addr, 0);
3600 return env->regs[10];
3601 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003602 force_sig(TARGET_SIGSEGV);
3603}
3604
Andreas Färber05390242012-02-25 03:37:53 +01003605long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003606{
3607 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3608 return -TARGET_ENOSYS;
3609}
3610
edgar_iglb6d3abd2008-02-28 11:29:27 +00003611#elif defined(TARGET_CRIS)
3612
3613struct target_sigcontext {
3614 struct target_pt_regs regs; /* needs to be first */
3615 uint32_t oldmask;
3616 uint32_t usp; /* usp before stacking this gunk on it */
3617};
3618
3619/* Signal frames. */
3620struct target_signal_frame {
3621 struct target_sigcontext sc;
3622 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003623 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003624};
3625
3626struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003627 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003628 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003629 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003630 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003631 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003632};
3633
Andreas Färber05390242012-02-25 03:37:53 +01003634static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003635{
edgar_igl9664d922008-03-03 22:23:53 +00003636 __put_user(env->regs[0], &sc->regs.r0);
3637 __put_user(env->regs[1], &sc->regs.r1);
3638 __put_user(env->regs[2], &sc->regs.r2);
3639 __put_user(env->regs[3], &sc->regs.r3);
3640 __put_user(env->regs[4], &sc->regs.r4);
3641 __put_user(env->regs[5], &sc->regs.r5);
3642 __put_user(env->regs[6], &sc->regs.r6);
3643 __put_user(env->regs[7], &sc->regs.r7);
3644 __put_user(env->regs[8], &sc->regs.r8);
3645 __put_user(env->regs[9], &sc->regs.r9);
3646 __put_user(env->regs[10], &sc->regs.r10);
3647 __put_user(env->regs[11], &sc->regs.r11);
3648 __put_user(env->regs[12], &sc->regs.r12);
3649 __put_user(env->regs[13], &sc->regs.r13);
3650 __put_user(env->regs[14], &sc->usp);
3651 __put_user(env->regs[15], &sc->regs.acr);
3652 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3653 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3654 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003655}
edgar_igl9664d922008-03-03 22:23:53 +00003656
Andreas Färber05390242012-02-25 03:37:53 +01003657static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003658{
edgar_igl9664d922008-03-03 22:23:53 +00003659 __get_user(env->regs[0], &sc->regs.r0);
3660 __get_user(env->regs[1], &sc->regs.r1);
3661 __get_user(env->regs[2], &sc->regs.r2);
3662 __get_user(env->regs[3], &sc->regs.r3);
3663 __get_user(env->regs[4], &sc->regs.r4);
3664 __get_user(env->regs[5], &sc->regs.r5);
3665 __get_user(env->regs[6], &sc->regs.r6);
3666 __get_user(env->regs[7], &sc->regs.r7);
3667 __get_user(env->regs[8], &sc->regs.r8);
3668 __get_user(env->regs[9], &sc->regs.r9);
3669 __get_user(env->regs[10], &sc->regs.r10);
3670 __get_user(env->regs[11], &sc->regs.r11);
3671 __get_user(env->regs[12], &sc->regs.r12);
3672 __get_user(env->regs[13], &sc->regs.r13);
3673 __get_user(env->regs[14], &sc->usp);
3674 __get_user(env->regs[15], &sc->regs.acr);
3675 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3676 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3677 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003678}
3679
Andreas Färber05390242012-02-25 03:37:53 +01003680static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003681{
edgar_igl9664d922008-03-03 22:23:53 +00003682 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003683 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003684 sp = (env->regs[R_SP] & ~3);
3685 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003686}
3687
pbrook624f7972008-05-31 16:11:38 +00003688static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003689 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003690{
3691 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003692 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003693 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003694
edgar_igl9664d922008-03-03 22:23:53 +00003695 frame_addr = get_sigframe(env, sizeof *frame);
3696 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003697 goto badframe;
3698
3699 /*
3700 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3701 * use this trampoline anymore but it sets it up for GDB.
3702 * In QEMU, using the trampoline simplifies things a bit so we use it.
3703 *
3704 * This is movu.w __NR_sigreturn, r9; break 13;
3705 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003706 __put_user(0x9c5f, frame->retcode+0);
3707 __put_user(TARGET_NR_sigreturn,
3708 frame->retcode + 1);
3709 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003710
3711 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003712 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003713
Riku Voipio0188fad2014-04-23 13:34:15 +03003714 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3715 __put_user(set->sig[i], &frame->extramask[i - 1]);
3716 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003717
3718 setup_sigcontext(&frame->sc, env);
3719
3720 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003721 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003722 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003723 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003724 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003725 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003726
edgar_igl9664d922008-03-03 22:23:53 +00003727 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003728 return;
3729 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003730 force_sig(TARGET_SIGSEGV);
3731}
3732
pbrook624f7972008-05-31 16:11:38 +00003733static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003734 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003735 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003736{
3737 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3738}
3739
Andreas Färber05390242012-02-25 03:37:53 +01003740long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003741{
3742 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003743 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003744 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003745 sigset_t set;
3746 int i;
3747
edgar_igl9664d922008-03-03 22:23:53 +00003748 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003749 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003750 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003751 goto badframe;
3752
3753 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003754 __get_user(target_set.sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003755 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003756 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003757 }
3758 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003759 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003760
3761 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003762 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003763 return env->regs[10];
3764 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003765 force_sig(TARGET_SIGSEGV);
3766}
3767
Andreas Färber05390242012-02-25 03:37:53 +01003768long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003769{
3770 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3771 return -TARGET_ENOSYS;
3772}
thsc3b5bc82007-12-02 06:31:25 +00003773
Jia Liud9627832012-07-20 15:50:52 +08003774#elif defined(TARGET_OPENRISC)
3775
3776struct target_sigcontext {
3777 struct target_pt_regs regs;
3778 abi_ulong oldmask;
3779 abi_ulong usp;
3780};
3781
3782struct target_ucontext {
3783 abi_ulong tuc_flags;
3784 abi_ulong tuc_link;
3785 target_stack_t tuc_stack;
3786 struct target_sigcontext tuc_mcontext;
3787 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3788};
3789
3790struct target_rt_sigframe {
3791 abi_ulong pinfo;
3792 uint64_t puc;
3793 struct target_siginfo info;
3794 struct target_sigcontext sc;
3795 struct target_ucontext uc;
3796 unsigned char retcode[16]; /* trampoline code */
3797};
3798
3799/* This is the asm-generic/ucontext.h version */
3800#if 0
3801static int restore_sigcontext(CPUOpenRISCState *regs,
3802 struct target_sigcontext *sc)
3803{
3804 unsigned int err = 0;
3805 unsigned long old_usp;
3806
3807 /* Alwys make any pending restarted system call return -EINTR */
3808 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3809
3810 /* restore the regs from &sc->regs (same as sc, since regs is first)
3811 * (sc is already checked for VERIFY_READ since the sigframe was
3812 * checked in sys_sigreturn previously)
3813 */
3814
3815 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3816 goto badframe;
3817 }
3818
3819 /* make sure the U-flag is set so user-mode cannot fool us */
3820
3821 regs->sr &= ~SR_SM;
3822
3823 /* restore the old USP as it was before we stacked the sc etc.
3824 * (we cannot just pop the sigcontext since we aligned the sp and
3825 * stuff after pushing it)
3826 */
3827
Riku Voipio1d8b5122014-04-23 10:26:05 +03003828 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003829 phx_signal("old_usp 0x%lx", old_usp);
3830
3831 __PHX__ REALLY /* ??? */
3832 wrusp(old_usp);
3833 regs->gpr[1] = old_usp;
3834
3835 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3836 * after this completes, but we don't use that mechanism. maybe we can
3837 * use it now ?
3838 */
3839
3840 return err;
3841
3842badframe:
3843 return 1;
3844}
3845#endif
3846
3847/* Set up a signal frame. */
3848
Riku Voipio41ecc722014-04-23 11:01:00 +03003849static void setup_sigcontext(struct target_sigcontext *sc,
Jia Liud9627832012-07-20 15:50:52 +08003850 CPUOpenRISCState *regs,
3851 unsigned long mask)
3852{
Jia Liud9627832012-07-20 15:50:52 +08003853 unsigned long usp = regs->gpr[1];
3854
3855 /* copy the regs. they are first in sc so we can use sc directly */
3856
Riku Voipio1d8b5122014-04-23 10:26:05 +03003857 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003858
3859 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3860 the signal handler. The frametype will be restored to its previous
3861 value in restore_sigcontext. */
3862 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3863
3864 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003865 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003866 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003867}
3868
3869static inline unsigned long align_sigframe(unsigned long sp)
3870{
3871 unsigned long i;
3872 i = sp & ~3UL;
3873 return i;
3874}
3875
3876static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3877 CPUOpenRISCState *regs,
3878 size_t frame_size)
3879{
3880 unsigned long sp = regs->gpr[1];
3881 int onsigstack = on_sig_stack(sp);
3882
3883 /* redzone */
3884 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03003885 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08003886 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3887 }
3888
3889 sp = align_sigframe(sp - frame_size);
3890
3891 /*
3892 * If we are on the alternate signal stack and would overflow it, don't.
3893 * Return an always-bogus address instead so we will die with SIGSEGV.
3894 */
3895
3896 if (onsigstack && !likely(on_sig_stack(sp))) {
3897 return -1L;
3898 }
3899
3900 return sp;
3901}
3902
Jia Liud9627832012-07-20 15:50:52 +08003903static void setup_rt_frame(int sig, struct target_sigaction *ka,
3904 target_siginfo_t *info,
3905 target_sigset_t *set, CPUOpenRISCState *env)
3906{
3907 int err = 0;
3908 abi_ulong frame_addr;
3909 unsigned long return_ip;
3910 struct target_rt_sigframe *frame;
3911 abi_ulong info_addr, uc_addr;
3912
Jia Liud9627832012-07-20 15:50:52 +08003913 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3914 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3915 goto give_sigsegv;
3916 }
3917
3918 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003919 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08003920 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003921 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08003922
3923 if (ka->sa_flags & SA_SIGINFO) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00003924 tswap_siginfo(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08003925 }
3926
3927 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03003928 __put_user(0, &frame->uc.tuc_flags);
3929 __put_user(0, &frame->uc.tuc_link);
3930 __put_user(target_sigaltstack_used.ss_sp,
3931 &frame->uc.tuc_stack.ss_sp);
3932 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3933 __put_user(target_sigaltstack_used.ss_size,
3934 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03003935 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08003936
3937 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3938
Jia Liud9627832012-07-20 15:50:52 +08003939 /* trampoline - the desired return ip is the retcode itself */
3940 return_ip = (unsigned long)&frame->retcode;
3941 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003942 __put_user(0xa960, (short *)(frame->retcode + 0));
3943 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
3944 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
3945 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08003946
3947 if (err) {
3948 goto give_sigsegv;
3949 }
3950
3951 /* TODO what is the current->exec_domain stuff and invmap ? */
3952
3953 /* Set up registers for signal handler */
3954 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
3955 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
3956 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
3957 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
3958 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
3959
3960 /* actually move the usp to reflect the stacked frame */
3961 env->gpr[1] = (unsigned long)frame;
3962
3963 return;
3964
3965give_sigsegv:
3966 unlock_user_struct(frame, frame_addr, 1);
3967 if (sig == TARGET_SIGSEGV) {
3968 ka->_sa_handler = TARGET_SIG_DFL;
3969 }
3970 force_sig(TARGET_SIGSEGV);
3971}
3972
3973long do_sigreturn(CPUOpenRISCState *env)
3974{
3975
3976 qemu_log("do_sigreturn: not implemented\n");
3977 return -TARGET_ENOSYS;
3978}
3979
3980long do_rt_sigreturn(CPUOpenRISCState *env)
3981{
3982 qemu_log("do_rt_sigreturn: not implemented\n");
3983 return -TARGET_ENOSYS;
3984}
3985/* TARGET_OPENRISC */
3986
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003987#elif defined(TARGET_S390X)
3988
3989#define __NUM_GPRS 16
3990#define __NUM_FPRS 16
3991#define __NUM_ACRS 16
3992
3993#define S390_SYSCALL_SIZE 2
3994#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
3995
3996#define _SIGCONTEXT_NSIG 64
3997#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
3998#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
3999#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4000#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4001#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4002
4003typedef struct {
4004 target_psw_t psw;
4005 target_ulong gprs[__NUM_GPRS];
4006 unsigned int acrs[__NUM_ACRS];
4007} target_s390_regs_common;
4008
4009typedef struct {
4010 unsigned int fpc;
4011 double fprs[__NUM_FPRS];
4012} target_s390_fp_regs;
4013
4014typedef struct {
4015 target_s390_regs_common regs;
4016 target_s390_fp_regs fpregs;
4017} target_sigregs;
4018
4019struct target_sigcontext {
4020 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4021 target_sigregs *sregs;
4022};
4023
4024typedef struct {
4025 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4026 struct target_sigcontext sc;
4027 target_sigregs sregs;
4028 int signo;
4029 uint8_t retcode[S390_SYSCALL_SIZE];
4030} sigframe;
4031
4032struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004033 target_ulong tuc_flags;
4034 struct target_ucontext *tuc_link;
4035 target_stack_t tuc_stack;
4036 target_sigregs tuc_mcontext;
4037 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004038};
4039
4040typedef struct {
4041 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4042 uint8_t retcode[S390_SYSCALL_SIZE];
4043 struct target_siginfo info;
4044 struct target_ucontext uc;
4045} rt_sigframe;
4046
4047static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004048get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004049{
4050 abi_ulong sp;
4051
4052 /* Default to using normal stack */
4053 sp = env->regs[15];
4054
4055 /* This is the X/Open sanctioned signal stack switching. */
4056 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4057 if (!sas_ss_flags(sp)) {
4058 sp = target_sigaltstack_used.ss_sp +
4059 target_sigaltstack_used.ss_size;
4060 }
4061 }
4062
4063 /* This is the legacy signal stack switching. */
4064 else if (/* FIXME !user_mode(regs) */ 0 &&
4065 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4066 ka->sa_restorer) {
4067 sp = (abi_ulong) ka->sa_restorer;
4068 }
4069
4070 return (sp - frame_size) & -8ul;
4071}
4072
Andreas Färber05390242012-02-25 03:37:53 +01004073static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004074{
4075 int i;
4076 //save_access_regs(current->thread.acrs); FIXME
4077
4078 /* Copy a 'clean' PSW mask to the user to avoid leaking
4079 information about whether PER is currently on. */
4080 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4081 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4082 for (i = 0; i < 16; i++) {
4083 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4084 }
4085 for (i = 0; i < 16; i++) {
4086 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4087 }
4088 /*
4089 * We have to store the fp registers to current->thread.fp_regs
4090 * to merge them with the emulated registers.
4091 */
4092 //save_fp_regs(&current->thread.fp_regs); FIXME
4093 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004094 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004095 }
4096}
4097
4098static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004099 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004100{
4101 sigframe *frame;
4102 abi_ulong frame_addr;
4103
4104 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4105 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4106 (unsigned long long)frame_addr);
4107 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4108 goto give_sigsegv;
4109 }
4110
4111 qemu_log("%s: 1\n", __FUNCTION__);
Riku Voipio0188fad2014-04-23 13:34:15 +03004112 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004113
4114 save_sigregs(env, &frame->sregs);
4115
4116 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4117 (abi_ulong *)&frame->sc.sregs);
4118
4119 /* Set up to return from userspace. If provided, use a stub
4120 already in userspace. */
4121 if (ka->sa_flags & TARGET_SA_RESTORER) {
4122 env->regs[14] = (unsigned long)
4123 ka->sa_restorer | PSW_ADDR_AMODE;
4124 } else {
4125 env->regs[14] = (unsigned long)
4126 frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004127 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4128 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004129 }
4130
4131 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004132 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004133
4134 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004135 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004136 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4137
4138 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004139 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004140
4141 /* We forgot to include these in the sigcontext.
4142 To avoid breaking binary compatibility, they are passed as args. */
4143 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4144 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4145
4146 /* Place signal number on stack to allow backtrace from handler. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004147 __put_user(env->regs[2], (int *) &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004148 unlock_user_struct(frame, frame_addr, 1);
4149 return;
4150
4151give_sigsegv:
4152 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004153 force_sig(TARGET_SIGSEGV);
4154}
4155
4156static void setup_rt_frame(int sig, struct target_sigaction *ka,
4157 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004158 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004159{
4160 int i;
4161 rt_sigframe *frame;
4162 abi_ulong frame_addr;
4163
4164 frame_addr = get_sigframe(ka, env, sizeof *frame);
4165 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4166 (unsigned long long)frame_addr);
4167 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4168 goto give_sigsegv;
4169 }
4170
4171 qemu_log("%s: 1\n", __FUNCTION__);
Peter Maydellf6c7a052015-01-08 12:19:48 +00004172 tswap_siginfo(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004173
4174 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004175 __put_user(0, &frame->uc.tuc_flags);
4176 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4177 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004178 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004179 &frame->uc.tuc_stack.ss_flags);
4180 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4181 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004182 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4183 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004184 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004185 }
4186
4187 /* Set up to return from userspace. If provided, use a stub
4188 already in userspace. */
4189 if (ka->sa_flags & TARGET_SA_RESTORER) {
4190 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4191 } else {
4192 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004193 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4194 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004195 }
4196
4197 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004198 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004199
4200 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004201 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004202 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4203
4204 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004205 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4206 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004207 return;
4208
4209give_sigsegv:
4210 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004211 force_sig(TARGET_SIGSEGV);
4212}
4213
4214static int
Andreas Färber05390242012-02-25 03:37:53 +01004215restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004216{
4217 int err = 0;
4218 int i;
4219
4220 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004221 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004222 }
4223
Riku Voipio1d8b5122014-04-23 10:26:05 +03004224 __get_user(env->psw.mask, &sc->regs.psw.mask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004225 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4226 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4227 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004228 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004229 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4230
4231 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004232 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004233 }
4234 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004235 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004236 }
4237
4238 return err;
4239}
4240
Andreas Färber05390242012-02-25 03:37:53 +01004241long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004242{
4243 sigframe *frame;
4244 abi_ulong frame_addr = env->regs[15];
4245 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4246 (unsigned long long)frame_addr);
4247 target_sigset_t target_set;
4248 sigset_t set;
4249
4250 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4251 goto badframe;
4252 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004253 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004254
4255 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004256 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004257
4258 if (restore_sigregs(env, &frame->sregs)) {
4259 goto badframe;
4260 }
4261
4262 unlock_user_struct(frame, frame_addr, 0);
4263 return env->regs[2];
4264
4265badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004266 force_sig(TARGET_SIGSEGV);
4267 return 0;
4268}
4269
Andreas Färber05390242012-02-25 03:37:53 +01004270long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004271{
4272 rt_sigframe *frame;
4273 abi_ulong frame_addr = env->regs[15];
4274 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4275 (unsigned long long)frame_addr);
4276 sigset_t set;
4277
4278 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4279 goto badframe;
4280 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004281 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004282
Alex Barcelo1c275922014-03-14 14:36:55 +00004283 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004284
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004285 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004286 goto badframe;
4287 }
4288
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004289 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004290 get_sp_from_cpustate(env)) == -EFAULT) {
4291 goto badframe;
4292 }
4293 unlock_user_struct(frame, frame_addr, 0);
4294 return env->regs[2];
4295
4296badframe:
4297 unlock_user_struct(frame, frame_addr, 0);
4298 force_sig(TARGET_SIGSEGV);
4299 return 0;
4300}
4301
Tom Musta61e75fe2014-06-30 08:13:38 -05004302#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004303
4304/* Size of dummy stack frame allocated when calling signal handler.
4305 See arch/powerpc/include/asm/ptrace.h. */
4306#if defined(TARGET_PPC64)
4307#define SIGNAL_FRAMESIZE 128
4308#else
4309#define SIGNAL_FRAMESIZE 64
4310#endif
4311
Tom Musta61e75fe2014-06-30 08:13:38 -05004312/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4313 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4314struct target_mcontext {
4315 target_ulong mc_gregs[48];
4316 /* Includes fpscr. */
4317 uint64_t mc_fregs[33];
4318 target_ulong mc_pad[2];
4319 /* We need to handle Altivec and SPE at the same time, which no
4320 kernel needs to do. Fortunately, the kernel defines this bit to
4321 be Altivec-register-large all the time, rather than trying to
4322 twiddle it based on the specific platform. */
4323 union {
4324 /* SPE vector registers. One extra for SPEFSCR. */
4325 uint32_t spe[33];
4326 /* Altivec vector registers. The packing of VSCR and VRSAVE
4327 varies depending on whether we're PPC64 or not: PPC64 splits
4328 them apart; PPC32 stuffs them together. */
4329#if defined(TARGET_PPC64)
4330#define QEMU_NVRREG 34
4331#else
4332#define QEMU_NVRREG 33
4333#endif
4334 ppc_avr_t altivec[QEMU_NVRREG];
4335#undef QEMU_NVRREG
4336 } mc_vregs __attribute__((__aligned__(16)));
4337};
4338
Nathan Froydbcd49332009-05-12 19:13:18 -07004339/* See arch/powerpc/include/asm/sigcontext.h. */
4340struct target_sigcontext {
4341 target_ulong _unused[4];
4342 int32_t signal;
4343#if defined(TARGET_PPC64)
4344 int32_t pad0;
4345#endif
4346 target_ulong handler;
4347 target_ulong oldmask;
4348 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004349#if defined(TARGET_PPC64)
4350 struct target_mcontext mcontext;
4351#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004352};
4353
4354/* Indices for target_mcontext.mc_gregs, below.
4355 See arch/powerpc/include/asm/ptrace.h for details. */
4356enum {
4357 TARGET_PT_R0 = 0,
4358 TARGET_PT_R1 = 1,
4359 TARGET_PT_R2 = 2,
4360 TARGET_PT_R3 = 3,
4361 TARGET_PT_R4 = 4,
4362 TARGET_PT_R5 = 5,
4363 TARGET_PT_R6 = 6,
4364 TARGET_PT_R7 = 7,
4365 TARGET_PT_R8 = 8,
4366 TARGET_PT_R9 = 9,
4367 TARGET_PT_R10 = 10,
4368 TARGET_PT_R11 = 11,
4369 TARGET_PT_R12 = 12,
4370 TARGET_PT_R13 = 13,
4371 TARGET_PT_R14 = 14,
4372 TARGET_PT_R15 = 15,
4373 TARGET_PT_R16 = 16,
4374 TARGET_PT_R17 = 17,
4375 TARGET_PT_R18 = 18,
4376 TARGET_PT_R19 = 19,
4377 TARGET_PT_R20 = 20,
4378 TARGET_PT_R21 = 21,
4379 TARGET_PT_R22 = 22,
4380 TARGET_PT_R23 = 23,
4381 TARGET_PT_R24 = 24,
4382 TARGET_PT_R25 = 25,
4383 TARGET_PT_R26 = 26,
4384 TARGET_PT_R27 = 27,
4385 TARGET_PT_R28 = 28,
4386 TARGET_PT_R29 = 29,
4387 TARGET_PT_R30 = 30,
4388 TARGET_PT_R31 = 31,
4389 TARGET_PT_NIP = 32,
4390 TARGET_PT_MSR = 33,
4391 TARGET_PT_ORIG_R3 = 34,
4392 TARGET_PT_CTR = 35,
4393 TARGET_PT_LNK = 36,
4394 TARGET_PT_XER = 37,
4395 TARGET_PT_CCR = 38,
4396 /* Yes, there are two registers with #39. One is 64-bit only. */
4397 TARGET_PT_MQ = 39,
4398 TARGET_PT_SOFTE = 39,
4399 TARGET_PT_TRAP = 40,
4400 TARGET_PT_DAR = 41,
4401 TARGET_PT_DSISR = 42,
4402 TARGET_PT_RESULT = 43,
4403 TARGET_PT_REGS_COUNT = 44
4404};
4405
Nathan Froydbcd49332009-05-12 19:13:18 -07004406
4407struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004408 target_ulong tuc_flags;
4409 target_ulong tuc_link; /* struct ucontext __user * */
4410 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004411#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004412 int32_t tuc_pad[7];
4413 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004414 points to uc_mcontext field */
4415#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004416 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004417#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004418 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004419 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004420#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004421 int32_t tuc_maskext[30];
4422 int32_t tuc_pad2[3];
4423 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004424#endif
4425};
4426
4427/* See arch/powerpc/kernel/signal_32.c. */
4428struct target_sigframe {
4429 struct target_sigcontext sctx;
4430 struct target_mcontext mctx;
4431 int32_t abigap[56];
4432};
4433
Tom Musta61e75fe2014-06-30 08:13:38 -05004434#if defined(TARGET_PPC64)
4435
4436#define TARGET_TRAMP_SIZE 6
4437
4438struct target_rt_sigframe {
4439 /* sys_rt_sigreturn requires the ucontext be the first field */
4440 struct target_ucontext uc;
4441 target_ulong _unused[2];
4442 uint32_t trampoline[TARGET_TRAMP_SIZE];
4443 target_ulong pinfo; /* struct siginfo __user * */
4444 target_ulong puc; /* void __user * */
4445 struct target_siginfo info;
4446 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4447 char abigap[288];
4448} __attribute__((aligned(16)));
4449
4450#else
4451
Nathan Froydbcd49332009-05-12 19:13:18 -07004452struct target_rt_sigframe {
4453 struct target_siginfo info;
4454 struct target_ucontext uc;
4455 int32_t abigap[56];
4456};
4457
Tom Musta61e75fe2014-06-30 08:13:38 -05004458#endif
4459
Tom Musta8d6ab332014-06-30 08:13:39 -05004460#if defined(TARGET_PPC64)
4461
4462struct target_func_ptr {
4463 target_ulong entry;
4464 target_ulong toc;
4465};
4466
4467#endif
4468
Nathan Froydbcd49332009-05-12 19:13:18 -07004469/* We use the mc_pad field for the signal return trampoline. */
4470#define tramp mc_pad
4471
4472/* See arch/powerpc/kernel/signal.c. */
4473static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004474 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004475 int frame_size)
4476{
4477 target_ulong oldsp, newsp;
4478
4479 oldsp = env->gpr[1];
4480
4481 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004482 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004483 oldsp = (target_sigaltstack_used.ss_sp
4484 + target_sigaltstack_used.ss_size);
4485 }
4486
4487 newsp = (oldsp - frame_size) & ~0xFUL;
4488
4489 return newsp;
4490}
4491
Tom Musta76781082014-06-30 08:13:37 -05004492static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004493{
4494 target_ulong msr = env->msr;
4495 int i;
4496 target_ulong ccr = 0;
4497
4498 /* In general, the kernel attempts to be intelligent about what it
4499 needs to save for Altivec/FP/SPE registers. We don't care that
4500 much, so we just go ahead and save everything. */
4501
4502 /* Save general registers. */
4503 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004504 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004505 }
Riku Voipioc650c002014-04-23 13:53:45 +03004506 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4507 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4508 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4509 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004510
4511 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4512 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4513 }
Riku Voipioc650c002014-04-23 13:53:45 +03004514 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004515
4516 /* Save Altivec registers if necessary. */
4517 if (env->insns_flags & PPC_ALTIVEC) {
4518 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004519 ppc_avr_t *avr = &env->avr[i];
4520 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004521
Riku Voipioc650c002014-04-23 13:53:45 +03004522 __put_user(avr->u64[0], &vreg->u64[0]);
4523 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004524 }
4525 /* Set MSR_VR in the saved MSR value to indicate that
4526 frame->mc_vregs contains valid data. */
4527 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004528 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4529 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004530 }
4531
4532 /* Save floating point registers. */
4533 if (env->insns_flags & PPC_FLOAT) {
4534 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004535 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004536 }
Riku Voipioc650c002014-04-23 13:53:45 +03004537 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004538 }
4539
4540 /* Save SPE registers. The kernel only saves the high half. */
4541 if (env->insns_flags & PPC_SPE) {
4542#if defined(TARGET_PPC64)
4543 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004544 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004545 }
4546#else
4547 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004548 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004549 }
4550#endif
4551 /* Set MSR_SPE in the saved MSR value to indicate that
4552 frame->mc_vregs contains valid data. */
4553 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004554 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004555 }
4556
4557 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004558 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004559}
Nathan Froydbcd49332009-05-12 19:13:18 -07004560
Tom Musta76781082014-06-30 08:13:37 -05004561static void encode_trampoline(int sigret, uint32_t *tramp)
4562{
Nathan Froydbcd49332009-05-12 19:13:18 -07004563 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4564 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004565 __put_user(0x38000000 | sigret, &tramp[0]);
4566 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004567 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004568}
4569
Riku Voipioc650c002014-04-23 13:53:45 +03004570static void restore_user_regs(CPUPPCState *env,
4571 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004572{
4573 target_ulong save_r2 = 0;
4574 target_ulong msr;
4575 target_ulong ccr;
4576
4577 int i;
4578
4579 if (!sig) {
4580 save_r2 = env->gpr[2];
4581 }
4582
4583 /* Restore general registers. */
4584 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004585 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004586 }
Riku Voipioc650c002014-04-23 13:53:45 +03004587 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4588 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4589 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4590 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4591 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004592
4593 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4594 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4595 }
4596
4597 if (!sig) {
4598 env->gpr[2] = save_r2;
4599 }
4600 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004601 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004602
4603 /* If doing signal return, restore the previous little-endian mode. */
4604 if (sig)
4605 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4606
4607 /* Restore Altivec registers if necessary. */
4608 if (env->insns_flags & PPC_ALTIVEC) {
4609 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004610 ppc_avr_t *avr = &env->avr[i];
4611 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004612
Riku Voipioc650c002014-04-23 13:53:45 +03004613 __get_user(avr->u64[0], &vreg->u64[0]);
4614 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004615 }
4616 /* Set MSR_VEC in the saved MSR value to indicate that
4617 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004618 __get_user(env->spr[SPR_VRSAVE],
4619 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004620 }
4621
4622 /* Restore floating point registers. */
4623 if (env->insns_flags & PPC_FLOAT) {
4624 uint64_t fpscr;
4625 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004626 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004627 }
Riku Voipioc650c002014-04-23 13:53:45 +03004628 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004629 env->fpscr = (uint32_t) fpscr;
4630 }
4631
4632 /* Save SPE registers. The kernel only saves the high half. */
4633 if (env->insns_flags & PPC_SPE) {
4634#if defined(TARGET_PPC64)
4635 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4636 uint32_t hi;
4637
Riku Voipioc650c002014-04-23 13:53:45 +03004638 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004639 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4640 }
4641#else
4642 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004643 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004644 }
4645#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004646 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004647 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004648}
4649
4650static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004651 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004652{
4653 struct target_sigframe *frame;
4654 struct target_sigcontext *sc;
4655 target_ulong frame_addr, newsp;
4656 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004657#if defined(TARGET_PPC64)
4658 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4659#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004660
4661 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4662 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4663 goto sigsegv;
4664 sc = &frame->sctx;
4665
Riku Voipio1d8b5122014-04-23 10:26:05 +03004666 __put_user(ka->_sa_handler, &sc->handler);
4667 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004668#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004669 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004670#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004671 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004672#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004673 __put_user(h2g(&frame->mctx), &sc->regs);
4674 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004675
4676 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004677 save_user_regs(env, &frame->mctx);
4678
4679 /* Construct the trampoline code on the stack. */
4680 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004681
4682 /* The kernel checks for the presence of a VDSO here. We don't
4683 emulate a vdso, so use a sigreturn system call. */
4684 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4685
4686 /* Turn off all fp exceptions. */
4687 env->fpscr = 0;
4688
4689 /* Create a stack frame for the caller of the handler. */
4690 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004691 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004692
4693 if (err)
4694 goto sigsegv;
4695
4696 /* Set up registers for signal handler. */
4697 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004698 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004699 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004700
4701#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004702 if (get_ppc64_abi(image) < 2) {
4703 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4704 struct target_func_ptr *handler =
4705 (struct target_func_ptr *)g2h(ka->_sa_handler);
4706 env->nip = tswapl(handler->entry);
4707 env->gpr[2] = tswapl(handler->toc);
4708 } else {
4709 /* ELFv2 PPC64 function pointers are entry points, but R12
4710 * must also be set */
4711 env->nip = tswapl((target_ulong) ka->_sa_handler);
4712 env->gpr[12] = env->nip;
4713 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004714#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004715 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004716#endif
4717
Nathan Froydbcd49332009-05-12 19:13:18 -07004718 /* Signal handlers are entered in big-endian mode. */
4719 env->msr &= ~MSR_LE;
4720
4721 unlock_user_struct(frame, frame_addr, 1);
4722 return;
4723
4724sigsegv:
4725 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004726 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004727 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004728}
4729
4730static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004731 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004732 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004733{
4734 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004735 uint32_t *trampptr = 0;
4736 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004737 target_ulong rt_sf_addr, newsp = 0;
4738 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004739#if defined(TARGET_PPC64)
4740 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4741#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004742
4743 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4744 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4745 goto sigsegv;
4746
Peter Maydellf6c7a052015-01-08 12:19:48 +00004747 tswap_siginfo(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004748
Riku Voipio1d8b5122014-04-23 10:26:05 +03004749 __put_user(0, &rt_sf->uc.tuc_flags);
4750 __put_user(0, &rt_sf->uc.tuc_link);
4751 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4752 &rt_sf->uc.tuc_stack.ss_sp);
4753 __put_user(sas_ss_flags(env->gpr[1]),
4754 &rt_sf->uc.tuc_stack.ss_flags);
4755 __put_user(target_sigaltstack_used.ss_size,
4756 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004757#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004758 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4759 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004760#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004761 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004762 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004763 }
4764
Tom Musta61e75fe2014-06-30 08:13:38 -05004765#if defined(TARGET_PPC64)
4766 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4767 trampptr = &rt_sf->trampoline[0];
4768#else
4769 mctx = &rt_sf->uc.tuc_mcontext;
4770 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4771#endif
4772
4773 save_user_regs(env, mctx);
4774 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004775
4776 /* The kernel checks for the presence of a VDSO here. We don't
4777 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004778 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004779
4780 /* Turn off all fp exceptions. */
4781 env->fpscr = 0;
4782
4783 /* Create a stack frame for the caller of the handler. */
4784 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004785 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004786
4787 if (err)
4788 goto sigsegv;
4789
4790 /* Set up registers for signal handler. */
4791 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004792 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004793 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4794 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4795 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004796
4797#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004798 if (get_ppc64_abi(image) < 2) {
4799 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4800 struct target_func_ptr *handler =
4801 (struct target_func_ptr *)g2h(ka->_sa_handler);
4802 env->nip = tswapl(handler->entry);
4803 env->gpr[2] = tswapl(handler->toc);
4804 } else {
4805 /* ELFv2 PPC64 function pointers are entry points, but R12
4806 * must also be set */
4807 env->nip = tswapl((target_ulong) ka->_sa_handler);
4808 env->gpr[12] = env->nip;
4809 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004810#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004811 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004812#endif
4813
Nathan Froydbcd49332009-05-12 19:13:18 -07004814 /* Signal handlers are entered in big-endian mode. */
4815 env->msr &= ~MSR_LE;
4816
4817 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4818 return;
4819
4820sigsegv:
4821 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004822 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004823 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004824
4825}
4826
Andreas Färber05390242012-02-25 03:37:53 +01004827long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004828{
4829 struct target_sigcontext *sc = NULL;
4830 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004831 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004832 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004833 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004834
4835 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4836 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4837 goto sigsegv;
4838
4839#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004840 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004841#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004842 __get_user(set.sig[0], &sc->oldmask);
4843 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004844#endif
4845 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004846 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004847
Riku Voipiof5f601a2014-04-23 13:00:17 +03004848 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004849 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4850 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004851 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004852
4853 unlock_user_struct(sr, sr_addr, 1);
4854 unlock_user_struct(sc, sc_addr, 1);
4855 return -TARGET_QEMU_ESIGRETURN;
4856
4857sigsegv:
4858 unlock_user_struct(sr, sr_addr, 1);
4859 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004860 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004861 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004862 return 0;
4863}
4864
4865/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004866static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004867{
4868 struct target_mcontext *mcp;
4869 target_ulong mcp_addr;
4870 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004871 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004872
Aurelien Jarno60e99242010-03-29 02:12:51 +02004873 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004874 sizeof (set)))
4875 return 1;
4876
Tom Musta19774ec2014-06-30 08:13:40 -05004877#if defined(TARGET_PPC64)
4878 mcp_addr = h2g(ucp) +
4879 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4880#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004881 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004882#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004883
4884 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4885 return 1;
4886
4887 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004888 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Riku Voipioc650c002014-04-23 13:53:45 +03004889 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004890
4891 unlock_user_struct(mcp, mcp_addr, 1);
4892 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004893}
4894
Andreas Färber05390242012-02-25 03:37:53 +01004895long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004896{
4897 struct target_rt_sigframe *rt_sf = NULL;
4898 target_ulong rt_sf_addr;
4899
4900 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4901 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4902 goto sigsegv;
4903
4904 if (do_setcontext(&rt_sf->uc, env, 1))
4905 goto sigsegv;
4906
4907 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004908 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004909 0, env->gpr[1]);
4910
4911 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4912 return -TARGET_QEMU_ESIGRETURN;
4913
4914sigsegv:
4915 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004916 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004917 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004918 return 0;
4919}
4920
Laurent Vivier492a8742009-08-03 16:12:17 +02004921#elif defined(TARGET_M68K)
4922
4923struct target_sigcontext {
4924 abi_ulong sc_mask;
4925 abi_ulong sc_usp;
4926 abi_ulong sc_d0;
4927 abi_ulong sc_d1;
4928 abi_ulong sc_a0;
4929 abi_ulong sc_a1;
4930 unsigned short sc_sr;
4931 abi_ulong sc_pc;
4932};
4933
4934struct target_sigframe
4935{
4936 abi_ulong pretcode;
4937 int sig;
4938 int code;
4939 abi_ulong psc;
4940 char retcode[8];
4941 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4942 struct target_sigcontext sc;
4943};
Laurent Vivier71811552009-08-03 16:12:18 +02004944
Anthony Liguoric227f092009-10-01 16:12:16 -05004945typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004946#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004947typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004948
4949typedef struct target_fpregset {
4950 int f_fpcntl[3];
4951 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05004952} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004953
4954struct target_mcontext {
4955 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05004956 target_gregset_t gregs;
4957 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004958};
4959
4960#define TARGET_MCONTEXT_VERSION 2
4961
4962struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004963 abi_ulong tuc_flags;
4964 abi_ulong tuc_link;
4965 target_stack_t tuc_stack;
4966 struct target_mcontext tuc_mcontext;
4967 abi_long tuc_filler[80];
4968 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02004969};
4970
4971struct target_rt_sigframe
4972{
4973 abi_ulong pretcode;
4974 int sig;
4975 abi_ulong pinfo;
4976 abi_ulong puc;
4977 char retcode[8];
4978 struct target_siginfo info;
4979 struct target_ucontext uc;
4980};
Laurent Vivier492a8742009-08-03 16:12:17 +02004981
Riku Voipio41ecc722014-04-23 11:01:00 +03004982static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
4983 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02004984{
Riku Voipio1d8b5122014-04-23 10:26:05 +03004985 __put_user(mask, &sc->sc_mask);
4986 __put_user(env->aregs[7], &sc->sc_usp);
4987 __put_user(env->dregs[0], &sc->sc_d0);
4988 __put_user(env->dregs[1], &sc->sc_d1);
4989 __put_user(env->aregs[0], &sc->sc_a0);
4990 __put_user(env->aregs[1], &sc->sc_a1);
4991 __put_user(env->sr, &sc->sc_sr);
4992 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02004993}
4994
Riku Voipio016d2e12014-04-23 11:19:48 +03004995static void
Andreas Färber05390242012-02-25 03:37:53 +01004996restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02004997{
Laurent Vivier492a8742009-08-03 16:12:17 +02004998 int temp;
4999
Riku Voipio1d8b5122014-04-23 10:26:05 +03005000 __get_user(env->aregs[7], &sc->sc_usp);
5001 __get_user(env->dregs[1], &sc->sc_d1);
5002 __get_user(env->aregs[0], &sc->sc_a0);
5003 __get_user(env->aregs[1], &sc->sc_a1);
5004 __get_user(env->pc, &sc->sc_pc);
5005 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005006 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5007
5008 *pd0 = tswapl(sc->sc_d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005009}
5010
5011/*
5012 * Determine which stack to use..
5013 */
5014static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005015get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5016 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005017{
5018 unsigned long sp;
5019
5020 sp = regs->aregs[7];
5021
5022 /* This is the X/Open sanctioned signal stack switching. */
5023 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5024 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5025 }
5026
5027 return ((sp - frame_size) & -8UL);
5028}
5029
5030static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005031 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005032{
5033 struct target_sigframe *frame;
5034 abi_ulong frame_addr;
5035 abi_ulong retcode_addr;
5036 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005037 int i;
5038
5039 frame_addr = get_sigframe(ka, env, sizeof *frame);
5040 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5041 goto give_sigsegv;
5042
Riku Voipio1d8b5122014-04-23 10:26:05 +03005043 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005044
5045 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005046 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005047
Riku Voipio41ecc722014-04-23 11:01:00 +03005048 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005049
5050 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005051 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005052 }
5053
5054 /* Set up to return from userspace. */
5055
5056 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005057 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005058
5059 /* moveq #,d0; trap #0 */
5060
Riku Voipio1d8b5122014-04-23 10:26:05 +03005061 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005062 (uint32_t *)(frame->retcode));
Laurent Vivier492a8742009-08-03 16:12:17 +02005063
Laurent Vivier492a8742009-08-03 16:12:17 +02005064 /* Set up to return from userspace */
5065
5066 env->aregs[7] = frame_addr;
5067 env->pc = ka->_sa_handler;
5068
5069 unlock_user_struct(frame, frame_addr, 1);
5070 return;
5071
5072give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005073 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005074}
5075
Laurent Vivier71811552009-08-03 16:12:18 +02005076static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005077 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005078{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005079 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005080
Riku Voipio1d8b5122014-04-23 10:26:05 +03005081 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5082 __put_user(env->dregs[0], &gregs[0]);
5083 __put_user(env->dregs[1], &gregs[1]);
5084 __put_user(env->dregs[2], &gregs[2]);
5085 __put_user(env->dregs[3], &gregs[3]);
5086 __put_user(env->dregs[4], &gregs[4]);
5087 __put_user(env->dregs[5], &gregs[5]);
5088 __put_user(env->dregs[6], &gregs[6]);
5089 __put_user(env->dregs[7], &gregs[7]);
5090 __put_user(env->aregs[0], &gregs[8]);
5091 __put_user(env->aregs[1], &gregs[9]);
5092 __put_user(env->aregs[2], &gregs[10]);
5093 __put_user(env->aregs[3], &gregs[11]);
5094 __put_user(env->aregs[4], &gregs[12]);
5095 __put_user(env->aregs[5], &gregs[13]);
5096 __put_user(env->aregs[6], &gregs[14]);
5097 __put_user(env->aregs[7], &gregs[15]);
5098 __put_user(env->pc, &gregs[16]);
5099 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005100
Riku Voipio1d8b5122014-04-23 10:26:05 +03005101 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005102}
5103
Andreas Färber05390242012-02-25 03:37:53 +01005104static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005105 struct target_ucontext *uc,
5106 int *pd0)
5107{
5108 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005109 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005110
Riku Voipio1d8b5122014-04-23 10:26:05 +03005111 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005112 if (temp != TARGET_MCONTEXT_VERSION)
5113 goto badframe;
5114
5115 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005116 __get_user(env->dregs[0], &gregs[0]);
5117 __get_user(env->dregs[1], &gregs[1]);
5118 __get_user(env->dregs[2], &gregs[2]);
5119 __get_user(env->dregs[3], &gregs[3]);
5120 __get_user(env->dregs[4], &gregs[4]);
5121 __get_user(env->dregs[5], &gregs[5]);
5122 __get_user(env->dregs[6], &gregs[6]);
5123 __get_user(env->dregs[7], &gregs[7]);
5124 __get_user(env->aregs[0], &gregs[8]);
5125 __get_user(env->aregs[1], &gregs[9]);
5126 __get_user(env->aregs[2], &gregs[10]);
5127 __get_user(env->aregs[3], &gregs[11]);
5128 __get_user(env->aregs[4], &gregs[12]);
5129 __get_user(env->aregs[5], &gregs[13]);
5130 __get_user(env->aregs[6], &gregs[14]);
5131 __get_user(env->aregs[7], &gregs[15]);
5132 __get_user(env->pc, &gregs[16]);
5133 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005134 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5135
5136 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005137 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005138
5139badframe:
5140 return 1;
5141}
5142
Laurent Vivier492a8742009-08-03 16:12:17 +02005143static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005144 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005145 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005146{
Laurent Vivier71811552009-08-03 16:12:18 +02005147 struct target_rt_sigframe *frame;
5148 abi_ulong frame_addr;
5149 abi_ulong retcode_addr;
5150 abi_ulong info_addr;
5151 abi_ulong uc_addr;
5152 int err = 0;
5153 int i;
5154
5155 frame_addr = get_sigframe(ka, env, sizeof *frame);
5156 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5157 goto give_sigsegv;
5158
Riku Voipio1d8b5122014-04-23 10:26:05 +03005159 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005160
5161 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005162 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005163
5164 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005165 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005166
Peter Maydellf6c7a052015-01-08 12:19:48 +00005167 tswap_siginfo(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005168
5169 /* Create the ucontext */
5170
Riku Voipio1d8b5122014-04-23 10:26:05 +03005171 __put_user(0, &frame->uc.tuc_flags);
5172 __put_user(0, &frame->uc.tuc_link);
5173 __put_user(target_sigaltstack_used.ss_sp,
5174 &frame->uc.tuc_stack.ss_sp);
5175 __put_user(sas_ss_flags(env->aregs[7]),
5176 &frame->uc.tuc_stack.ss_flags);
5177 __put_user(target_sigaltstack_used.ss_size,
5178 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005179 err |= target_rt_setup_ucontext(&frame->uc, env);
5180
5181 if (err)
5182 goto give_sigsegv;
5183
5184 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005185 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005186 }
5187
5188 /* Set up to return from userspace. */
5189
5190 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005191 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005192
5193 /* moveq #,d0; notb d0; trap #0 */
5194
Riku Voipio1d8b5122014-04-23 10:26:05 +03005195 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005196 (uint32_t *)(frame->retcode + 0));
5197 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005198
5199 if (err)
5200 goto give_sigsegv;
5201
5202 /* Set up to return from userspace */
5203
5204 env->aregs[7] = frame_addr;
5205 env->pc = ka->_sa_handler;
5206
5207 unlock_user_struct(frame, frame_addr, 1);
5208 return;
5209
5210give_sigsegv:
5211 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005212 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005213}
5214
Andreas Färber05390242012-02-25 03:37:53 +01005215long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005216{
5217 struct target_sigframe *frame;
5218 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005219 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005220 sigset_t set;
5221 int d0, i;
5222
5223 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5224 goto badframe;
5225
5226 /* set blocked signals */
5227
Riku Voipiof5f601a2014-04-23 13:00:17 +03005228 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005229
5230 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005231 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005232 }
5233
5234 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005235 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005236
5237 /* restore registers */
5238
Riku Voipio016d2e12014-04-23 11:19:48 +03005239 restore_sigcontext(env, &frame->sc, &d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005240
5241 unlock_user_struct(frame, frame_addr, 0);
5242 return d0;
5243
5244badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005245 force_sig(TARGET_SIGSEGV);
5246 return 0;
5247}
5248
Andreas Färber05390242012-02-25 03:37:53 +01005249long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005250{
Laurent Vivier71811552009-08-03 16:12:18 +02005251 struct target_rt_sigframe *frame;
5252 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005253 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005254 sigset_t set;
5255 int d0;
5256
5257 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5258 goto badframe;
5259
5260 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005261 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005262
5263 /* restore registers */
5264
5265 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5266 goto badframe;
5267
5268 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005269 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005270 0, get_sp_from_cpustate(env)) == -EFAULT)
5271 goto badframe;
5272
5273 unlock_user_struct(frame, frame_addr, 0);
5274 return d0;
5275
5276badframe:
5277 unlock_user_struct(frame, frame_addr, 0);
5278 force_sig(TARGET_SIGSEGV);
5279 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005280}
5281
Richard Henderson6049f4f2009-12-27 18:30:03 -08005282#elif defined(TARGET_ALPHA)
5283
5284struct target_sigcontext {
5285 abi_long sc_onstack;
5286 abi_long sc_mask;
5287 abi_long sc_pc;
5288 abi_long sc_ps;
5289 abi_long sc_regs[32];
5290 abi_long sc_ownedfp;
5291 abi_long sc_fpregs[32];
5292 abi_ulong sc_fpcr;
5293 abi_ulong sc_fp_control;
5294 abi_ulong sc_reserved1;
5295 abi_ulong sc_reserved2;
5296 abi_ulong sc_ssize;
5297 abi_ulong sc_sbase;
5298 abi_ulong sc_traparg_a0;
5299 abi_ulong sc_traparg_a1;
5300 abi_ulong sc_traparg_a2;
5301 abi_ulong sc_fp_trap_pc;
5302 abi_ulong sc_fp_trigger_sum;
5303 abi_ulong sc_fp_trigger_inst;
5304};
5305
5306struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005307 abi_ulong tuc_flags;
5308 abi_ulong tuc_link;
5309 abi_ulong tuc_osf_sigmask;
5310 target_stack_t tuc_stack;
5311 struct target_sigcontext tuc_mcontext;
5312 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005313};
5314
5315struct target_sigframe {
5316 struct target_sigcontext sc;
5317 unsigned int retcode[3];
5318};
5319
5320struct target_rt_sigframe {
5321 target_siginfo_t info;
5322 struct target_ucontext uc;
5323 unsigned int retcode[3];
5324};
5325
5326#define INSN_MOV_R30_R16 0x47fe0410
5327#define INSN_LDI_R0 0x201f0000
5328#define INSN_CALLSYS 0x00000083
5329
Riku Voipio41ecc722014-04-23 11:01:00 +03005330static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005331 abi_ulong frame_addr, target_sigset_t *set)
5332{
Riku Voipio41ecc722014-04-23 11:01:00 +03005333 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005334
Riku Voipio1d8b5122014-04-23 10:26:05 +03005335 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5336 __put_user(set->sig[0], &sc->sc_mask);
5337 __put_user(env->pc, &sc->sc_pc);
5338 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005339
5340 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005341 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005342 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005343 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005344
5345 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005346 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005347 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005348 __put_user(0, &sc->sc_fpregs[31]);
5349 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005350
Riku Voipio1d8b5122014-04-23 10:26:05 +03005351 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5352 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5353 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005354}
5355
Riku Voipio016d2e12014-04-23 11:19:48 +03005356static void restore_sigcontext(CPUAlphaState *env,
Andreas Färber05390242012-02-25 03:37:53 +01005357 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005358{
5359 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005360 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005361
Riku Voipio1d8b5122014-04-23 10:26:05 +03005362 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005363
5364 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005365 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005366 }
5367 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005368 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005369 }
5370
Riku Voipio1d8b5122014-04-23 10:26:05 +03005371 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005372 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005373}
5374
5375static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005376 CPUAlphaState *env,
5377 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005378{
5379 abi_ulong sp = env->ir[IR_SP];
5380
5381 /* This is the X/Open sanctioned signal stack switching. */
5382 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5383 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5384 }
5385 return (sp - framesize) & -32;
5386}
5387
5388static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005389 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005390{
5391 abi_ulong frame_addr, r26;
5392 struct target_sigframe *frame;
5393 int err = 0;
5394
5395 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5396 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5397 goto give_sigsegv;
5398 }
5399
Riku Voipio41ecc722014-04-23 11:01:00 +03005400 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005401
5402 if (ka->sa_restorer) {
5403 r26 = ka->sa_restorer;
5404 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005405 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5406 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5407 &frame->retcode[1]);
5408 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005409 /* imb() */
5410 r26 = frame_addr;
5411 }
5412
5413 unlock_user_struct(frame, frame_addr, 1);
5414
5415 if (err) {
5416 give_sigsegv:
5417 if (sig == TARGET_SIGSEGV) {
5418 ka->_sa_handler = TARGET_SIG_DFL;
5419 }
5420 force_sig(TARGET_SIGSEGV);
5421 }
5422
5423 env->ir[IR_RA] = r26;
5424 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5425 env->ir[IR_A0] = sig;
5426 env->ir[IR_A1] = 0;
5427 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5428 env->ir[IR_SP] = frame_addr;
5429}
5430
5431static void setup_rt_frame(int sig, struct target_sigaction *ka,
5432 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005433 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005434{
5435 abi_ulong frame_addr, r26;
5436 struct target_rt_sigframe *frame;
5437 int i, err = 0;
5438
5439 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5440 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5441 goto give_sigsegv;
5442 }
5443
Peter Maydellf6c7a052015-01-08 12:19:48 +00005444 tswap_siginfo(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005445
Riku Voipio1d8b5122014-04-23 10:26:05 +03005446 __put_user(0, &frame->uc.tuc_flags);
5447 __put_user(0, &frame->uc.tuc_link);
5448 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5449 __put_user(target_sigaltstack_used.ss_sp,
5450 &frame->uc.tuc_stack.ss_sp);
5451 __put_user(sas_ss_flags(env->ir[IR_SP]),
5452 &frame->uc.tuc_stack.ss_flags);
5453 __put_user(target_sigaltstack_used.ss_size,
5454 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005455 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005456 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005457 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005458 }
5459
5460 if (ka->sa_restorer) {
5461 r26 = ka->sa_restorer;
5462 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005463 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5464 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5465 &frame->retcode[1]);
5466 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005467 /* imb(); */
5468 r26 = frame_addr;
5469 }
5470
5471 if (err) {
5472 give_sigsegv:
5473 if (sig == TARGET_SIGSEGV) {
5474 ka->_sa_handler = TARGET_SIG_DFL;
5475 }
5476 force_sig(TARGET_SIGSEGV);
5477 }
5478
5479 env->ir[IR_RA] = r26;
5480 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5481 env->ir[IR_A0] = sig;
5482 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5483 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5484 env->ir[IR_SP] = frame_addr;
5485}
5486
Andreas Färber05390242012-02-25 03:37:53 +01005487long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005488{
5489 struct target_sigcontext *sc;
5490 abi_ulong sc_addr = env->ir[IR_A0];
5491 target_sigset_t target_set;
5492 sigset_t set;
5493
5494 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5495 goto badframe;
5496 }
5497
5498 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005499 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005500
5501 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005502 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005503
Riku Voipio016d2e12014-04-23 11:19:48 +03005504 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005505 unlock_user_struct(sc, sc_addr, 0);
5506 return env->ir[IR_V0];
5507
5508 badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005509 force_sig(TARGET_SIGSEGV);
5510}
5511
Andreas Färber05390242012-02-25 03:37:53 +01005512long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005513{
5514 abi_ulong frame_addr = env->ir[IR_A0];
5515 struct target_rt_sigframe *frame;
5516 sigset_t set;
5517
5518 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5519 goto badframe;
5520 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005521 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005522 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005523
Riku Voipio016d2e12014-04-23 11:19:48 +03005524 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005525 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005526 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005527 0, env->ir[IR_SP]) == -EFAULT) {
5528 goto badframe;
5529 }
5530
5531 unlock_user_struct(frame, frame_addr, 0);
5532 return env->ir[IR_V0];
5533
5534
5535 badframe:
5536 unlock_user_struct(frame, frame_addr, 0);
5537 force_sig(TARGET_SIGSEGV);
5538}
5539
Chen Gangbf0f60a2015-09-27 08:10:18 +08005540#elif defined(TARGET_TILEGX)
5541
5542struct target_sigcontext {
5543 union {
5544 /* General-purpose registers. */
5545 abi_ulong gregs[56];
5546 struct {
5547 abi_ulong __gregs[53];
5548 abi_ulong tp; /* Aliases gregs[TREG_TP]. */
5549 abi_ulong sp; /* Aliases gregs[TREG_SP]. */
5550 abi_ulong lr; /* Aliases gregs[TREG_LR]. */
5551 };
5552 };
5553 abi_ulong pc; /* Program counter. */
5554 abi_ulong ics; /* In Interrupt Critical Section? */
5555 abi_ulong faultnum; /* Fault number. */
5556 abi_ulong pad[5];
5557};
5558
5559struct target_ucontext {
5560 abi_ulong tuc_flags;
5561 abi_ulong tuc_link;
5562 target_stack_t tuc_stack;
5563 struct target_sigcontext tuc_mcontext;
5564 target_sigset_t tuc_sigmask; /* mask last for extensibility */
5565};
5566
5567struct target_rt_sigframe {
5568 unsigned char save_area[16]; /* caller save area */
5569 struct target_siginfo info;
5570 struct target_ucontext uc;
5571};
5572
5573static void setup_sigcontext(struct target_sigcontext *sc,
5574 CPUArchState *env, int signo)
5575{
5576 int i;
5577
5578 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5579 __put_user(env->regs[i], &sc->gregs[i]);
5580 }
5581
5582 __put_user(env->pc, &sc->pc);
5583 __put_user(0, &sc->ics);
5584 __put_user(signo, &sc->faultnum);
5585}
5586
5587static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
5588{
5589 int i;
5590
5591 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5592 __get_user(env->regs[i], &sc->gregs[i]);
5593 }
5594
5595 __get_user(env->pc, &sc->pc);
5596}
5597
5598static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
5599 size_t frame_size)
5600{
5601 unsigned long sp = env->regs[TILEGX_R_SP];
5602
5603 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
5604 return -1UL;
5605 }
5606
5607 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
5608 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5609 }
5610
5611 sp -= frame_size;
5612 sp &= -16UL;
5613 return sp;
5614}
5615
5616static void setup_rt_frame(int sig, struct target_sigaction *ka,
5617 target_siginfo_t *info,
5618 target_sigset_t *set, CPUArchState *env)
5619{
5620 abi_ulong frame_addr;
5621 struct target_rt_sigframe *frame;
5622 unsigned long restorer;
5623
5624 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5625 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5626 goto give_sigsegv;
5627 }
5628
5629 /* Always write at least the signal number for the stack backtracer. */
5630 if (ka->sa_flags & TARGET_SA_SIGINFO) {
5631 /* At sigreturn time, restore the callee-save registers too. */
5632 tswap_siginfo(&frame->info, info);
5633 /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
5634 } else {
5635 __put_user(info->si_signo, &frame->info.si_signo);
5636 }
5637
5638 /* Create the ucontext. */
5639 __put_user(0, &frame->uc.tuc_flags);
5640 __put_user(0, &frame->uc.tuc_link);
5641 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
5642 __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
5643 &frame->uc.tuc_stack.ss_flags);
5644 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
5645 setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
5646
5647 restorer = (unsigned long) do_rt_sigreturn;
5648 if (ka->sa_flags & TARGET_SA_RESTORER) {
5649 restorer = (unsigned long) ka->sa_restorer;
5650 }
5651 env->pc = (unsigned long) ka->_sa_handler;
5652 env->regs[TILEGX_R_SP] = (unsigned long) frame;
5653 env->regs[TILEGX_R_LR] = restorer;
5654 env->regs[0] = (unsigned long) sig;
5655 env->regs[1] = (unsigned long) &frame->info;
5656 env->regs[2] = (unsigned long) &frame->uc;
5657 /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
5658
5659 unlock_user_struct(frame, frame_addr, 1);
5660 return;
5661
5662give_sigsegv:
5663 if (sig == TARGET_SIGSEGV) {
5664 ka->_sa_handler = TARGET_SIG_DFL;
5665 }
5666 force_sig(TARGET_SIGSEGV /* , current */);
5667}
5668
5669long do_rt_sigreturn(CPUTLGState *env)
5670{
5671 abi_ulong frame_addr = env->regs[TILEGX_R_SP];
5672 struct target_rt_sigframe *frame;
5673 sigset_t set;
5674
5675 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5676 goto badframe;
5677 }
5678 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
5679 do_sigprocmask(SIG_SETMASK, &set, NULL);
5680
5681 restore_sigcontext(env, &frame->uc.tuc_mcontext);
5682 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
5683 uc.tuc_stack),
5684 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
5685 goto badframe;
5686 }
5687
5688 unlock_user_struct(frame, frame_addr, 0);
5689 return env->regs[TILEGX_R_RE];
5690
5691
5692 badframe:
5693 unlock_user_struct(frame, frame_addr, 0);
5694 force_sig(TARGET_SIGSEGV);
5695}
5696
bellardb346ff42003-06-15 20:05:50 +00005697#else
5698
pbrook624f7972008-05-31 16:11:38 +00005699static void setup_frame(int sig, struct target_sigaction *ka,
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_frame: not implemented\n");
5703}
5704
pbrook624f7972008-05-31 16:11:38 +00005705static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005706 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005707 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005708{
5709 fprintf(stderr, "setup_rt_frame: not implemented\n");
5710}
5711
Andreas Färber9349b4f2012-03-14 01:38:32 +01005712long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005713{
5714 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005715 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005716}
5717
Andreas Färber9349b4f2012-03-14 01:38:32 +01005718long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005719{
5720 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005721 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005722}
5723
bellard66fb9762003-03-23 01:06:05 +00005724#endif
5725
Andreas Färber9349b4f2012-03-14 01:38:32 +01005726void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005727{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005728 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005729 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005730 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005731 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005732 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005733 struct emulated_sigtable *k;
5734 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005735 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005736 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005737
pbrook624f7972008-05-31 16:11:38 +00005738 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005739 return;
5740
pbrook624f7972008-05-31 16:11:38 +00005741 /* FIXME: This is not threadsafe. */
5742 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005743 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5744 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005745 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005746 k++;
bellard31e31b82003-02-18 22:55:36 +00005747 }
5748 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005749 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005750 return;
bellard66fb9762003-03-23 01:06:05 +00005751
bellard31e31b82003-02-18 22:55:36 +00005752 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005753#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005754 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005755#endif
5756 /* dequeue signal */
5757 q = k->first;
5758 k->first = q->next;
5759 if (!k->first)
5760 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005761
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005762 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005763 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005764 sa = NULL;
5765 handler = TARGET_SIG_IGN;
5766 } else {
5767 sa = &sigact_table[sig - 1];
5768 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005769 }
bellard66fb9762003-03-23 01:06:05 +00005770
Peter Maydella7ec0f92014-03-14 14:36:56 +00005771 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5772 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5773 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5774 * because it got a real MMU fault), and treat as if default handler.
5775 */
5776 handler = TARGET_SIG_DFL;
5777 }
5778
bellard66fb9762003-03-23 01:06:05 +00005779 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005780 /* default handler : ignore some signal. The other are job control or fatal */
5781 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5782 kill(getpid(),SIGSTOP);
5783 } else if (sig != TARGET_SIGCHLD &&
5784 sig != TARGET_SIGURG &&
5785 sig != TARGET_SIGWINCH &&
5786 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005787 force_sig(sig);
5788 }
5789 } else if (handler == TARGET_SIG_IGN) {
5790 /* ignore sig */
5791 } else if (handler == TARGET_SIG_ERR) {
5792 force_sig(sig);
5793 } else {
bellard9de5e442003-03-23 16:49:39 +00005794 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005795 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005796 /* SA_NODEFER indicates that the current signal should not be
5797 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005798 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005799 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005800
bellard9de5e442003-03-23 16:49:39 +00005801 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005802 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005803 /* save the previous blocked signal state to restore it at the
5804 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005805 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005806
bellardbc8a22c2003-03-30 21:02:40 +00005807 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005808#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005809 {
5810 CPUX86State *env = cpu_env;
5811 if (env->eflags & VM_MASK)
5812 save_v86_state(env);
5813 }
5814#endif
bellard9de5e442003-03-23 16:49:39 +00005815 /* prepare the stack frame of the virtual CPU */
Chen Gangd0924a22015-09-12 23:32:30 +08005816#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
Chen Gangbf0f60a2015-09-27 08:10:18 +08005817 || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)
Richard Hendersonff970902013-02-10 10:30:42 -08005818 /* These targets do not have traditional signals. */
5819 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5820#else
pbrook624f7972008-05-31 16:11:38 +00005821 if (sa->sa_flags & TARGET_SA_SIGINFO)
5822 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005823 else
pbrook624f7972008-05-31 16:11:38 +00005824 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005825#endif
pbrook624f7972008-05-31 16:11:38 +00005826 if (sa->sa_flags & TARGET_SA_RESETHAND)
5827 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005828 }
bellard66fb9762003-03-23 01:06:05 +00005829 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005830 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005831}