blob: 962111cfdfabe9fd8406f9bfa32f0fac17e684c4 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Peter Maydelld39594e2016-01-26 18:17:02 +000019#include "qemu/osdep.h"
bellard31e31b82003-02-18 22:55:36 +000020#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030021#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000022
bellard3ef693a2003-03-23 20:17:16 +000023#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000024#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000025#include "target_signal.h"
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +010026#include "trace.h"
bellard66fb9762003-03-23 01:06:05 +000027
blueswir1249c4c32008-10-05 11:09:37 +000028static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000029 .ss_sp = 0,
30 .ss_size = 0,
31 .ss_flags = TARGET_SS_DISABLE,
32};
33
pbrook624f7972008-05-31 16:11:38 +000034static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000035
ths5fafdf22007-09-16 21:08:06 +000036static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000037 void *puc);
38
Arnaud Patard3ca05582009-03-30 01:18:20 +020039static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000040 [SIGHUP] = TARGET_SIGHUP,
41 [SIGINT] = TARGET_SIGINT,
42 [SIGQUIT] = TARGET_SIGQUIT,
43 [SIGILL] = TARGET_SIGILL,
44 [SIGTRAP] = TARGET_SIGTRAP,
45 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000046/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGBUS] = TARGET_SIGBUS,
48 [SIGFPE] = TARGET_SIGFPE,
49 [SIGKILL] = TARGET_SIGKILL,
50 [SIGUSR1] = TARGET_SIGUSR1,
51 [SIGSEGV] = TARGET_SIGSEGV,
52 [SIGUSR2] = TARGET_SIGUSR2,
53 [SIGPIPE] = TARGET_SIGPIPE,
54 [SIGALRM] = TARGET_SIGALRM,
55 [SIGTERM] = TARGET_SIGTERM,
56#ifdef SIGSTKFLT
57 [SIGSTKFLT] = TARGET_SIGSTKFLT,
58#endif
59 [SIGCHLD] = TARGET_SIGCHLD,
60 [SIGCONT] = TARGET_SIGCONT,
61 [SIGSTOP] = TARGET_SIGSTOP,
62 [SIGTSTP] = TARGET_SIGTSTP,
63 [SIGTTIN] = TARGET_SIGTTIN,
64 [SIGTTOU] = TARGET_SIGTTOU,
65 [SIGURG] = TARGET_SIGURG,
66 [SIGXCPU] = TARGET_SIGXCPU,
67 [SIGXFSZ] = TARGET_SIGXFSZ,
68 [SIGVTALRM] = TARGET_SIGVTALRM,
69 [SIGPROF] = TARGET_SIGPROF,
70 [SIGWINCH] = TARGET_SIGWINCH,
71 [SIGIO] = TARGET_SIGIO,
72 [SIGPWR] = TARGET_SIGPWR,
73 [SIGSYS] = TARGET_SIGSYS,
74 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000075 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080076 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000077 To fix this properly we need to do manual signal delivery multiplexed
78 over a single host signal. */
79 [__SIGRTMIN] = __SIGRTMAX,
80 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000081};
Arnaud Patard3ca05582009-03-30 01:18:20 +020082static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000083
thsa04e1342007-09-27 13:57:58 +000084static inline int on_sig_stack(unsigned long sp)
85{
86 return (sp - target_sigaltstack_used.ss_sp
87 < target_sigaltstack_used.ss_size);
88}
89
90static inline int sas_ss_flags(unsigned long sp)
91{
92 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
93 : on_sig_stack(sp) ? SS_ONSTACK : 0);
94}
95
pbrook1d9d8b52009-04-16 15:17:02 +000096int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +000097{
Andreas Schwab167c50d2013-07-02 14:04:12 +010098 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +000099 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000100 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000101}
102
pbrook4cb05962008-05-30 18:05:19 +0000103int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000104{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100105 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000106 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000107 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
Anthony Liguoric227f092009-10-01 16:12:16 -0500110static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000111{
112 memset(set, 0, sizeof(*set));
113}
114
Anthony Liguoric227f092009-10-01 16:12:16 -0500115static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000116{
117 signum--;
118 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
119 set->sig[signum / TARGET_NSIG_BPW] |= mask;
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000123{
124 signum--;
125 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
126 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000130 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000131{
132 int i;
pbrookf5545b52008-05-30 22:37:07 +0000133 target_sigemptyset(d);
134 for (i = 1; i <= TARGET_NSIG; i++) {
135 if (sigismember(s, i)) {
136 target_sigaddset(d, host_to_target_signal(i));
137 }
bellard9e5f5282003-07-13 17:33:54 +0000138 }
bellard66fb9762003-03-23 01:06:05 +0000139}
140
Anthony Liguoric227f092009-10-01 16:12:16 -0500141void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000142{
Anthony Liguoric227f092009-10-01 16:12:16 -0500143 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000144 int i;
145
146 host_to_target_sigset_internal(&d1, s);
147 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200148 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000149}
150
blueswir18fcd3692008-08-17 20:26:25 +0000151static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500152 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000153{
154 int i;
pbrookf5545b52008-05-30 22:37:07 +0000155 sigemptyset(d);
156 for (i = 1; i <= TARGET_NSIG; i++) {
157 if (target_sigismember(s, i)) {
158 sigaddset(d, target_to_host_signal(i));
159 }
160 }
bellard66fb9762003-03-23 01:06:05 +0000161}
162
Anthony Liguoric227f092009-10-01 16:12:16 -0500163void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000164{
Anthony Liguoric227f092009-10-01 16:12:16 -0500165 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000166 int i;
167
168 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200169 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000170 target_to_host_sigset_internal(d, &s1);
171}
ths3b46e622007-09-17 08:09:54 +0000172
blueswir1992f48a2007-10-14 16:27:31 +0000173void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000174 const sigset_t *sigset)
175{
Anthony Liguoric227f092009-10-01 16:12:16 -0500176 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000177 host_to_target_sigset(&d, sigset);
178 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000179}
180
ths5fafdf22007-09-16 21:08:06 +0000181void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000182 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000183{
Anthony Liguoric227f092009-10-01 16:12:16 -0500184 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000185 int i;
186
187 d.sig[0] = *old_sigset;
188 for(i = 1;i < TARGET_NSIG_WORDS; i++)
189 d.sig[i] = 0;
190 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000191}
192
Alex Barcelo1c275922014-03-14 14:36:55 +0000193/* Wrapper for sigprocmask function
194 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
195 * are host signal set, not guest ones. This wraps the sigprocmask host calls
196 * that should be protected (calls originated from guest)
197 */
198int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
199{
Peter Maydella7ec0f92014-03-14 14:36:56 +0000200 int ret;
201 sigset_t val;
202 sigset_t *temp = NULL;
203 CPUState *cpu = thread_cpu;
204 TaskState *ts = (TaskState *)cpu->opaque;
205 bool segv_was_blocked = ts->sigsegv_blocked;
206
207 if (set) {
208 bool has_sigsegv = sigismember(set, SIGSEGV);
209 val = *set;
210 temp = &val;
211
212 sigdelset(temp, SIGSEGV);
213
214 switch (how) {
215 case SIG_BLOCK:
216 if (has_sigsegv) {
217 ts->sigsegv_blocked = true;
218 }
219 break;
220 case SIG_UNBLOCK:
221 if (has_sigsegv) {
222 ts->sigsegv_blocked = false;
223 }
224 break;
225 case SIG_SETMASK:
226 ts->sigsegv_blocked = has_sigsegv;
227 break;
228 default:
229 g_assert_not_reached();
230 }
231 }
232
233 ret = sigprocmask(how, temp, oldset);
234
235 if (oldset && segv_was_blocked) {
236 sigaddset(oldset, SIGSEGV);
237 }
238
239 return ret;
Alex Barcelo1c275922014-03-14 14:36:55 +0000240}
241
bellard9de5e442003-03-23 16:49:39 +0000242/* siginfo conversion */
243
Anthony Liguoric227f092009-10-01 16:12:16 -0500244static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000245 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000246{
Richard Hendersona05c6402012-09-15 11:34:20 -0700247 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000248 tinfo->si_signo = sig;
249 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000250 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700251
252 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
253 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
254 /* Should never come here, but who knows. The information for
255 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000256 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700257 } else if (sig == TARGET_SIGIO) {
258 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000259 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700260 } else if (sig == TARGET_SIGCHLD) {
261 tinfo->_sifields._sigchld._pid = info->si_pid;
262 tinfo->_sifields._sigchld._uid = info->si_uid;
263 tinfo->_sifields._sigchld._status
264 = host_to_target_waitstatus(info->si_status);
265 tinfo->_sifields._sigchld._utime = info->si_utime;
266 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000267 } else if (sig >= TARGET_SIGRTMIN) {
268 tinfo->_sifields._rt._pid = info->si_pid;
269 tinfo->_sifields._rt._uid = info->si_uid;
270 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700271 tinfo->_sifields._rt._sigval.sival_ptr
272 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000273 }
bellard66fb9762003-03-23 01:06:05 +0000274}
275
Anthony Liguoric227f092009-10-01 16:12:16 -0500276static void tswap_siginfo(target_siginfo_t *tinfo,
277 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000278{
Richard Hendersona05c6402012-09-15 11:34:20 -0700279 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000280 tinfo->si_signo = tswap32(sig);
281 tinfo->si_errno = tswap32(info->si_errno);
282 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700283
284 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
285 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
286 tinfo->_sifields._sigfault._addr
287 = tswapal(info->_sifields._sigfault._addr);
288 } else if (sig == TARGET_SIGIO) {
289 tinfo->_sifields._sigpoll._band
290 = tswap32(info->_sifields._sigpoll._band);
291 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
292 } else if (sig == TARGET_SIGCHLD) {
293 tinfo->_sifields._sigchld._pid
294 = tswap32(info->_sifields._sigchld._pid);
295 tinfo->_sifields._sigchld._uid
296 = tswap32(info->_sifields._sigchld._uid);
297 tinfo->_sifields._sigchld._status
298 = tswap32(info->_sifields._sigchld._status);
299 tinfo->_sifields._sigchld._utime
300 = tswapal(info->_sifields._sigchld._utime);
301 tinfo->_sifields._sigchld._stime
302 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000303 } else if (sig >= TARGET_SIGRTMIN) {
304 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
305 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700306 tinfo->_sifields._rt._sigval.sival_ptr
307 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000308 }
309}
310
311
Anthony Liguoric227f092009-10-01 16:12:16 -0500312void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000313{
314 host_to_target_siginfo_noswap(tinfo, info);
315 tswap_siginfo(tinfo, tinfo);
316}
317
318/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000319/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500320void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000321{
322 info->si_signo = tswap32(tinfo->si_signo);
323 info->si_errno = tswap32(tinfo->si_errno);
324 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000325 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
326 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000327 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200328 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000329}
330
aurel32ca587a82008-12-18 22:44:13 +0000331static int fatal_signal (int sig)
332{
333 switch (sig) {
334 case TARGET_SIGCHLD:
335 case TARGET_SIGURG:
336 case TARGET_SIGWINCH:
337 /* Ignored by default. */
338 return 0;
339 case TARGET_SIGCONT:
340 case TARGET_SIGSTOP:
341 case TARGET_SIGTSTP:
342 case TARGET_SIGTTIN:
343 case TARGET_SIGTTOU:
344 /* Job control signals. */
345 return 0;
346 default:
347 return 1;
348 }
349}
350
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300351/* returns 1 if given signal should dump core if not handled */
352static int core_dump_signal(int sig)
353{
354 switch (sig) {
355 case TARGET_SIGABRT:
356 case TARGET_SIGFPE:
357 case TARGET_SIGILL:
358 case TARGET_SIGQUIT:
359 case TARGET_SIGSEGV:
360 case TARGET_SIGTRAP:
361 case TARGET_SIGBUS:
362 return (1);
363 default:
364 return (0);
365 }
366}
367
bellard31e31b82003-02-18 22:55:36 +0000368void signal_init(void)
369{
370 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000371 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000372 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000373 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000374
bellard9e5f5282003-07-13 17:33:54 +0000375 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200376 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000377 if (host_to_target_signal_table[i] == 0)
378 host_to_target_signal_table[i] = i;
379 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200380 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000381 j = host_to_target_signal_table[i];
382 target_to_host_signal_table[j] = i;
383 }
ths3b46e622007-09-17 08:09:54 +0000384
bellard9de5e442003-03-23 16:49:39 +0000385 /* set all host signal handlers. ALL signals are blocked during
386 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000387 memset(sigact_table, 0, sizeof(sigact_table));
388
bellard9de5e442003-03-23 16:49:39 +0000389 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000390 act.sa_flags = SA_SIGINFO;
391 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000392 for(i = 1; i <= TARGET_NSIG; i++) {
393 host_sig = target_to_host_signal(i);
394 sigaction(host_sig, NULL, &oact);
395 if (oact.sa_sigaction == (void *)SIG_IGN) {
396 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
397 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
398 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
399 }
400 /* If there's already a handler installed then something has
401 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000402 /* Install some handlers for our own use. We need at least
403 SIGSEGV and SIGBUS, to detect exceptions. We can not just
404 trap all signals because it affects syscall interrupt
405 behavior. But do trap all default-fatal signals. */
406 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000407 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000408 }
bellard31e31b82003-02-18 22:55:36 +0000409}
410
bellard66fb9762003-03-23 01:06:05 +0000411/* signal queue handling */
412
Andreas Färber9349b4f2012-03-14 01:38:32 +0100413static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000414{
Andreas Färber0429a972013-08-26 18:14:44 +0200415 CPUState *cpu = ENV_GET_CPU(env);
416 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000417 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000418 if (!q)
419 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000420 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000421 return q;
422}
423
Andreas Färber9349b4f2012-03-14 01:38:32 +0100424static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000425{
Andreas Färber0429a972013-08-26 18:14:44 +0200426 CPUState *cpu = ENV_GET_CPU(env);
427 TaskState *ts = cpu->opaque;
428
pbrook624f7972008-05-31 16:11:38 +0000429 q->next = ts->first_free;
430 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000431}
432
bellard9de5e442003-03-23 16:49:39 +0000433/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200434static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000435{
Andreas Färber0429a972013-08-26 18:14:44 +0200436 CPUState *cpu = thread_cpu;
437 CPUArchState *env = cpu->env_ptr;
438 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300439 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000440 struct sigaction act;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100441
Riku Voipio66393fb2009-12-04 15:16:32 +0200442 host_sig = target_to_host_signal(target_sig);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100443 trace_user_force_sig(env, target_sig, host_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200444 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000445
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300446 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200447 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300448 stop_all_tasks();
449 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200450 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300451 }
452 if (core_dumped) {
453 /* we already dumped the core of target process, we don't want
454 * a coredump of qemu itself */
455 struct rlimit nodump;
456 getrlimit(RLIMIT_CORE, &nodump);
457 nodump.rlim_cur=0;
458 setrlimit(RLIMIT_CORE, &nodump);
459 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200460 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300461 }
462
Stefan Weil0c587512011-04-28 17:20:32 +0200463 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000464 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
465 * a negative value. To get the proper exit code we need to
466 * actually die from an uncaught signal. Here the default signal
467 * handler is installed, we send ourself a signal and we wait for
468 * it to arrive. */
469 sigfillset(&act.sa_mask);
470 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000471 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000472 sigaction(host_sig, &act, NULL);
473
474 /* For some reason raise(host_sig) doesn't send the signal when
475 * statically linked on x86-64. */
476 kill(getpid(), host_sig);
477
478 /* Make sure the signal isn't masked (just reuse the mask inside
479 of act) */
480 sigdelset(&act.sa_mask, host_sig);
481 sigsuspend(&act.sa_mask);
482
483 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000484 abort();
bellard66fb9762003-03-23 01:06:05 +0000485}
486
bellard9de5e442003-03-23 16:49:39 +0000487/* queue a signal so that it will be send to the virtual CPU as soon
488 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100489int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000490{
Andreas Färber0429a972013-08-26 18:14:44 +0200491 CPUState *cpu = ENV_GET_CPU(env);
492 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000493 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000494 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000495 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000496 int queue;
bellard66fb9762003-03-23 01:06:05 +0000497
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100498 trace_user_queue_signal(env, sig);
pbrook624f7972008-05-31 16:11:38 +0000499 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000500 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000501 handler = sigact_table[sig - 1]._sa_handler;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000502
503 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
504 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
505 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
506 * because it got a real MMU fault). A blocked SIGSEGV in that
507 * situation is treated as if using the default handler. This is
508 * not correct if some other process has randomly sent us a SIGSEGV
509 * via kill(), but that is not easy to distinguish at this point,
510 * so we assume it doesn't happen.
511 */
512 handler = TARGET_SIG_DFL;
513 }
514
aurel32ca587a82008-12-18 22:44:13 +0000515 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000516 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
517 kill(getpid(),SIGSTOP);
518 return 0;
519 } else
bellard66fb9762003-03-23 01:06:05 +0000520 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000521 if (sig != TARGET_SIGCHLD &&
522 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000523 sig != TARGET_SIGWINCH &&
524 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000525 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000526 } else {
527 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000528 }
aurel32ca587a82008-12-18 22:44:13 +0000529 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000530 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000531 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000532 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000533 force_sig(sig);
534 } else {
bellard9de5e442003-03-23 16:49:39 +0000535 pq = &k->first;
536 if (sig < TARGET_SIGRTMIN) {
537 /* if non real time signal, we queue exactly one signal */
538 if (!k->pending)
539 q = &k->info;
540 else
541 return 0;
542 } else {
543 if (!k->pending) {
544 /* first signal */
545 q = &k->info;
546 } else {
pbrook624f7972008-05-31 16:11:38 +0000547 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000548 if (!q)
549 return -EAGAIN;
550 while (*pq != NULL)
551 pq = &(*pq)->next;
552 }
553 }
554 *pq = q;
555 q->info = *info;
556 q->next = NULL;
557 k->pending = 1;
558 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000559 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000560 return 1; /* indicates that the signal was queued */
561 }
562}
563
ths5fafdf22007-09-16 21:08:06 +0000564static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000565 void *puc)
566{
Andreas Färbera2247f82013-06-09 19:47:04 +0200567 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000568 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500569 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000570
571 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000572 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000573 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000574 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000575 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000576 return;
577 }
578
579 /* get target signal number */
580 sig = host_to_target_signal(host_signum);
581 if (sig < 1 || sig > TARGET_NSIG)
582 return;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100583 trace_user_host_signal(env, host_signum, sig);
bellard9de5e442003-03-23 16:49:39 +0000584 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200585 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000586 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200587 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000588 }
bellard31e31b82003-02-18 22:55:36 +0000589}
590
ths0da46a62007-10-20 20:23:07 +0000591/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000592/* compare linux/kernel/signal.c:do_sigaltstack() */
593abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000594{
595 int ret;
596 struct target_sigaltstack oss;
597
598 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000599 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000600 {
601 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
602 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
603 __put_user(sas_ss_flags(sp), &oss.ss_flags);
604 }
605
bellard579a97f2007-11-11 14:26:47 +0000606 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000607 {
bellard579a97f2007-11-11 14:26:47 +0000608 struct target_sigaltstack *uss;
609 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500610 size_t minstacksize = TARGET_MINSIGSTKSZ;
611
612#if defined(TARGET_PPC64)
613 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
614 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
615 if (get_ppc64_abi(image) > 1) {
616 minstacksize = 4096;
617 }
618#endif
thsa04e1342007-09-27 13:57:58 +0000619
ths0da46a62007-10-20 20:23:07 +0000620 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300621 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000622 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300623 }
624 __get_user(ss.ss_sp, &uss->ss_sp);
625 __get_user(ss.ss_size, &uss->ss_size);
626 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000627 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000628
ths0da46a62007-10-20 20:23:07 +0000629 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000630 if (on_sig_stack(sp))
631 goto out;
632
ths0da46a62007-10-20 20:23:07 +0000633 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000634 if (ss.ss_flags != TARGET_SS_DISABLE
635 && ss.ss_flags != TARGET_SS_ONSTACK
636 && ss.ss_flags != 0)
637 goto out;
638
639 if (ss.ss_flags == TARGET_SS_DISABLE) {
640 ss.ss_size = 0;
641 ss.ss_sp = 0;
642 } else {
ths0da46a62007-10-20 20:23:07 +0000643 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500644 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000645 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500646 }
thsa04e1342007-09-27 13:57:58 +0000647 }
648
649 target_sigaltstack_used.ss_sp = ss.ss_sp;
650 target_sigaltstack_used.ss_size = ss.ss_size;
651 }
652
bellard579a97f2007-11-11 14:26:47 +0000653 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000654 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000655 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000656 goto out;
thsa04e1342007-09-27 13:57:58 +0000657 }
658
659 ret = 0;
660out:
661 return ret;
662}
663
ths0da46a62007-10-20 20:23:07 +0000664/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000665int do_sigaction(int sig, const struct target_sigaction *act,
666 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000667{
pbrook624f7972008-05-31 16:11:38 +0000668 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000669 struct sigaction act1;
670 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000671 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000672
ths2a913eb2008-11-27 15:46:25 +0000673 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000674 return -EINVAL;
675 k = &sigact_table[sig - 1];
bellard66fb9762003-03-23 01:06:05 +0000676 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800677 __put_user(k->_sa_handler, &oact->_sa_handler);
678 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000679#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800680 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000681#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800682 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000683 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000684 }
685 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000686 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800687 __get_user(k->_sa_handler, &act->_sa_handler);
688 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000689#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800690 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000691#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800692 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000693 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000694
695 /* we update the host linux signal state */
696 host_sig = target_to_host_signal(sig);
697 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
698 sigfillset(&act1.sa_mask);
699 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000700 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000701 act1.sa_flags |= SA_RESTART;
702 /* NOTE: it is important to update the host kernel signal
703 ignore state to avoid getting unexpected interrupted
704 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000705 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000706 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000707 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000708 if (fatal_signal (sig))
709 act1.sa_sigaction = host_signal_handler;
710 else
711 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000712 } else {
713 act1.sa_sigaction = host_signal_handler;
714 }
ths0da46a62007-10-20 20:23:07 +0000715 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000716 }
bellard66fb9762003-03-23 01:06:05 +0000717 }
ths0da46a62007-10-20 20:23:07 +0000718 return ret;
bellard66fb9762003-03-23 01:06:05 +0000719}
bellard31e31b82003-02-18 22:55:36 +0000720
bellard459a4012007-11-11 19:45:10 +0000721#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000722
723/* from the Linux kernel */
724
725struct target_fpreg {
726 uint16_t significand[4];
727 uint16_t exponent;
728};
729
730struct target_fpxreg {
731 uint16_t significand[4];
732 uint16_t exponent;
733 uint16_t padding[3];
734};
735
736struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000737 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000738};
739
740struct target_fpstate {
741 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000742 abi_ulong cw;
743 abi_ulong sw;
744 abi_ulong tag;
745 abi_ulong ipoff;
746 abi_ulong cssel;
747 abi_ulong dataoff;
748 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000749 struct target_fpreg _st[8];
750 uint16_t status;
751 uint16_t magic; /* 0xffff = regular FPU data only */
752
753 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000754 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
755 abi_ulong mxcsr;
756 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000757 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
758 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000759 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000760};
761
762#define X86_FXSR_MAGIC 0x0000
763
764struct target_sigcontext {
765 uint16_t gs, __gsh;
766 uint16_t fs, __fsh;
767 uint16_t es, __esh;
768 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000769 abi_ulong edi;
770 abi_ulong esi;
771 abi_ulong ebp;
772 abi_ulong esp;
773 abi_ulong ebx;
774 abi_ulong edx;
775 abi_ulong ecx;
776 abi_ulong eax;
777 abi_ulong trapno;
778 abi_ulong err;
779 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000780 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000781 abi_ulong eflags;
782 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000783 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000784 abi_ulong fpstate; /* pointer */
785 abi_ulong oldmask;
786 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000787};
788
bellard66fb9762003-03-23 01:06:05 +0000789struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000790 abi_ulong tuc_flags;
791 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500792 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000793 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500794 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000795};
796
797struct sigframe
798{
blueswir1992f48a2007-10-14 16:27:31 +0000799 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000800 int sig;
801 struct target_sigcontext sc;
802 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000803 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000804 char retcode[8];
805};
806
807struct rt_sigframe
808{
blueswir1992f48a2007-10-14 16:27:31 +0000809 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000810 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000811 abi_ulong pinfo;
812 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000813 struct target_siginfo info;
814 struct target_ucontext uc;
815 struct target_fpstate fpstate;
816 char retcode[8];
817};
818
819/*
820 * Set up a signal frame.
821 */
822
bellard66fb9762003-03-23 01:06:05 +0000823/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300824static void setup_sigcontext(struct target_sigcontext *sc,
825 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
826 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000827{
Andreas Färber27103422013-08-26 08:31:06 +0200828 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200829 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000830
bellard579a97f2007-11-11 14:26:47 +0000831 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300832 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
833 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
834 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
835 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
836 __put_user(env->regs[R_EDI], &sc->edi);
837 __put_user(env->regs[R_ESI], &sc->esi);
838 __put_user(env->regs[R_EBP], &sc->ebp);
839 __put_user(env->regs[R_ESP], &sc->esp);
840 __put_user(env->regs[R_EBX], &sc->ebx);
841 __put_user(env->regs[R_EDX], &sc->edx);
842 __put_user(env->regs[R_ECX], &sc->ecx);
843 __put_user(env->regs[R_EAX], &sc->eax);
844 __put_user(cs->exception_index, &sc->trapno);
845 __put_user(env->error_code, &sc->err);
846 __put_user(env->eip, &sc->eip);
847 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
848 __put_user(env->eflags, &sc->eflags);
849 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
850 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000851
bellard28be6232007-11-11 22:23:38 +0000852 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000853 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000854 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300855 __put_user(magic, &fpstate->magic);
856 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000857
bellard66fb9762003-03-23 01:06:05 +0000858 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300859 __put_user(mask, &sc->oldmask);
860 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000861}
862
863/*
864 * Determine which stack to use..
865 */
866
bellard579a97f2007-11-11 14:26:47 +0000867static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000868get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000869{
870 unsigned long esp;
871
872 /* Default to using normal stack */
873 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000874 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000875 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000876 if (sas_ss_flags(esp) == 0)
877 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
878 }
bellard66fb9762003-03-23 01:06:05 +0000879
880 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000881 else
bellarda52c7572003-06-21 13:14:12 +0000882 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000883 !(ka->sa_flags & TARGET_SA_RESTORER) &&
884 ka->sa_restorer) {
885 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000886 }
bellard579a97f2007-11-11 14:26:47 +0000887 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000888}
889
bellard579a97f2007-11-11 14:26:47 +0000890/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000891static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500892 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000893{
bellard579a97f2007-11-11 14:26:47 +0000894 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000895 struct sigframe *frame;
Riku Voipio7df2fa32014-04-23 10:34:53 +0300896 int i;
bellard66fb9762003-03-23 01:06:05 +0000897
bellard579a97f2007-11-11 14:26:47 +0000898 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100899 trace_user_setup_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000900
bellard579a97f2007-11-11 14:26:47 +0000901 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000902 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000903
Peter Maydellb6e2c932015-01-08 12:19:43 +0000904 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000905
bellard28be6232007-11-11 22:23:38 +0000906 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
907 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000908
Riku Voipio7df2fa32014-04-23 10:34:53 +0300909 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
910 __put_user(set->sig[i], &frame->extramask[i - 1]);
911 }
bellard66fb9762003-03-23 01:06:05 +0000912
913 /* Set up to return from userspace. If provided, use a stub
914 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000915 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300916 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000917 } else {
bellard775b58d2007-11-11 16:22:17 +0000918 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000919 abi_ulong retcode_addr;
920 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300921 __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000922 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000923 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300924 __put_user(val16, (uint16_t *)(frame->retcode+0));
925 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000926 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300927 __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000928 }
929
bellard66fb9762003-03-23 01:06:05 +0000930
931 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000932 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000933 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000934
935 cpu_x86_load_seg(env, R_DS, __USER_DS);
936 cpu_x86_load_seg(env, R_ES, __USER_DS);
937 cpu_x86_load_seg(env, R_SS, __USER_DS);
938 cpu_x86_load_seg(env, R_CS, __USER_CS);
939 env->eflags &= ~TF_MASK;
940
bellard579a97f2007-11-11 14:26:47 +0000941 unlock_user_struct(frame, frame_addr, 1);
942
bellard66fb9762003-03-23 01:06:05 +0000943 return;
944
945give_sigsegv:
946 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000947 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000948 force_sig(TARGET_SIGSEGV /* , current */);
949}
950
bellard579a97f2007-11-11 14:26:47 +0000951/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000952static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500953 target_siginfo_t *info,
954 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000955{
bellard28be6232007-11-11 22:23:38 +0000956 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000957 struct rt_sigframe *frame;
Riku Voipio0188fad2014-04-23 13:34:15 +0300958 int i;
bellard66fb9762003-03-23 01:06:05 +0000959
bellard579a97f2007-11-11 14:26:47 +0000960 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100961 trace_user_setup_rt_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000962
bellard579a97f2007-11-11 14:26:47 +0000963 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000964 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000965
Peter Maydellb6e2c932015-01-08 12:19:43 +0000966 __put_user(sig, &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000967 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300968 __put_user(addr, &frame->pinfo);
bellard28be6232007-11-11 22:23:38 +0000969 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300970 __put_user(addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +0000971 tswap_siginfo(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +0000972
973 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300974 __put_user(0, &frame->uc.tuc_flags);
975 __put_user(0, &frame->uc.tuc_link);
976 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
977 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
978 &frame->uc.tuc_stack.ss_flags);
979 __put_user(target_sigaltstack_used.ss_size,
980 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +0300981 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
982 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
983
Riku Voipio0188fad2014-04-23 13:34:15 +0300984 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
985 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
986 }
bellard66fb9762003-03-23 01:06:05 +0000987
988 /* Set up to return from userspace. If provided, use a stub
989 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000990 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300991 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000992 } else {
bellard775b58d2007-11-11 16:22:17 +0000993 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000994 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300995 __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000996 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300997 __put_user(0xb8, (char *)(frame->retcode+0));
998 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000999 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001000 __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +00001001 }
1002
bellard66fb9762003-03-23 01:06:05 +00001003 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +00001004 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +00001005 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001006
1007 cpu_x86_load_seg(env, R_DS, __USER_DS);
1008 cpu_x86_load_seg(env, R_ES, __USER_DS);
1009 cpu_x86_load_seg(env, R_SS, __USER_DS);
1010 cpu_x86_load_seg(env, R_CS, __USER_CS);
1011 env->eflags &= ~TF_MASK;
1012
bellard579a97f2007-11-11 14:26:47 +00001013 unlock_user_struct(frame, frame_addr, 1);
1014
bellard66fb9762003-03-23 01:06:05 +00001015 return;
1016
1017give_sigsegv:
1018 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001019 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001020 force_sig(TARGET_SIGSEGV /* , current */);
1021}
1022
1023static int
1024restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1025{
1026 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001027 abi_ulong fpstate_addr;
1028 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001029
bellard28be6232007-11-11 22:23:38 +00001030 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1031 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1032 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1033 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001034
bellard28be6232007-11-11 22:23:38 +00001035 env->regs[R_EDI] = tswapl(sc->edi);
1036 env->regs[R_ESI] = tswapl(sc->esi);
1037 env->regs[R_EBP] = tswapl(sc->ebp);
1038 env->regs[R_ESP] = tswapl(sc->esp);
1039 env->regs[R_EBX] = tswapl(sc->ebx);
1040 env->regs[R_EDX] = tswapl(sc->edx);
1041 env->regs[R_ECX] = tswapl(sc->ecx);
1042 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001043
Mike McCormack9a826d72011-06-01 15:14:37 +09001044 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1045 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001046
bellard28be6232007-11-11 22:23:38 +00001047 tmpflags = tswapl(sc->eflags);
1048 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1049 // regs->orig_eax = -1; /* disable syscall checks */
1050
1051 fpstate_addr = tswapl(sc->fpstate);
1052 if (fpstate_addr != 0) {
1053 if (!access_ok(VERIFY_READ, fpstate_addr,
1054 sizeof(struct target_fpstate)))
1055 goto badframe;
1056 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001057 }
1058
bellard28be6232007-11-11 22:23:38 +00001059 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001060 return err;
bellard66fb9762003-03-23 01:06:05 +00001061badframe:
1062 return 1;
bellard66fb9762003-03-23 01:06:05 +00001063}
1064
1065long do_sigreturn(CPUX86State *env)
1066{
bellard579a97f2007-11-11 14:26:47 +00001067 struct sigframe *frame;
1068 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001069 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001070 sigset_t set;
1071 int eax, i;
1072
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001073 trace_user_do_sigreturn(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001074 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1075 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001076 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001077 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001078 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001079 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001080 }
bellard66fb9762003-03-23 01:06:05 +00001081
bellard92319442004-06-19 16:58:13 +00001082 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001083 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001084
bellard66fb9762003-03-23 01:06:05 +00001085 /* restore registers */
1086 if (restore_sigcontext(env, &frame->sc, &eax))
1087 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001088 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001089 return eax;
1090
1091badframe:
bellard579a97f2007-11-11 14:26:47 +00001092 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001093 force_sig(TARGET_SIGSEGV);
1094 return 0;
1095}
1096
1097long do_rt_sigreturn(CPUX86State *env)
1098{
bellard28be6232007-11-11 22:23:38 +00001099 abi_ulong frame_addr;
1100 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001101 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001102 int eax;
1103
bellard28be6232007-11-11 22:23:38 +00001104 frame_addr = env->regs[R_ESP] - 4;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001105 trace_user_do_rt_sigreturn(env, frame_addr);
bellard28be6232007-11-11 22:23:38 +00001106 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1107 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001108 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001109 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001110
bellardb8076a72005-04-07 22:20:31 +00001111 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001112 goto badframe;
1113
bellard28be6232007-11-11 22:23:38 +00001114 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1115 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001116 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001117
bellard28be6232007-11-11 22:23:38 +00001118 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001119 return eax;
1120
1121badframe:
bellard28be6232007-11-11 22:23:38 +00001122 unlock_user_struct(frame, frame_addr, 0);
1123 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001124 return 0;
1125}
1126
Andreas Schwab1744aea2013-09-03 20:12:16 +01001127#elif defined(TARGET_AARCH64)
1128
1129struct target_sigcontext {
1130 uint64_t fault_address;
1131 /* AArch64 registers */
1132 uint64_t regs[31];
1133 uint64_t sp;
1134 uint64_t pc;
1135 uint64_t pstate;
1136 /* 4K reserved for FP/SIMD state and future expansion */
1137 char __reserved[4096] __attribute__((__aligned__(16)));
1138};
1139
1140struct target_ucontext {
1141 abi_ulong tuc_flags;
1142 abi_ulong tuc_link;
1143 target_stack_t tuc_stack;
1144 target_sigset_t tuc_sigmask;
1145 /* glibc uses a 1024-bit sigset_t */
1146 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1147 /* last for future expansion */
1148 struct target_sigcontext tuc_mcontext;
1149};
1150
1151/*
1152 * Header to be used at the beginning of structures extending the user
1153 * context. Such structures must be placed after the rt_sigframe on the stack
1154 * and be 16-byte aligned. The last structure must be a dummy one with the
1155 * magic and size set to 0.
1156 */
1157struct target_aarch64_ctx {
1158 uint32_t magic;
1159 uint32_t size;
1160};
1161
1162#define TARGET_FPSIMD_MAGIC 0x46508001
1163
1164struct target_fpsimd_context {
1165 struct target_aarch64_ctx head;
1166 uint32_t fpsr;
1167 uint32_t fpcr;
1168 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1169};
1170
1171/*
1172 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1173 * user space as it will change with the addition of new context. User space
1174 * should check the magic/size information.
1175 */
1176struct target_aux_context {
1177 struct target_fpsimd_context fpsimd;
1178 /* additional context to be added before "end" */
1179 struct target_aarch64_ctx end;
1180};
1181
1182struct target_rt_sigframe {
1183 struct target_siginfo info;
1184 struct target_ucontext uc;
1185 uint64_t fp;
1186 uint64_t lr;
1187 uint32_t tramp[2];
1188};
1189
1190static int target_setup_sigframe(struct target_rt_sigframe *sf,
1191 CPUARMState *env, target_sigset_t *set)
1192{
1193 int i;
1194 struct target_aux_context *aux =
1195 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1196
1197 /* set up the stack frame for unwinding */
1198 __put_user(env->xregs[29], &sf->fp);
1199 __put_user(env->xregs[30], &sf->lr);
1200
1201 for (i = 0; i < 31; i++) {
1202 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1203 }
1204 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1205 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001206 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001207
Peter Maydell7af03922014-05-01 18:36:17 +01001208 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001209
1210 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1211 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1212 }
1213
1214 for (i = 0; i < 32; i++) {
1215#ifdef TARGET_WORDS_BIGENDIAN
1216 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1217 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1218#else
1219 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1220 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1221#endif
1222 }
Will Newtone0ee1382014-01-04 22:15:48 +00001223 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1224 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001225 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1226 __put_user(sizeof(struct target_fpsimd_context),
1227 &aux->fpsimd.head.size);
1228
1229 /* set the "end" magic */
1230 __put_user(0, &aux->end.magic);
1231 __put_user(0, &aux->end.size);
1232
1233 return 0;
1234}
1235
1236static int target_restore_sigframe(CPUARMState *env,
1237 struct target_rt_sigframe *sf)
1238{
1239 sigset_t set;
1240 int i;
1241 struct target_aux_context *aux =
1242 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001243 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001244 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001245
1246 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001247 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001248
1249 for (i = 0; i < 31; i++) {
1250 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1251 }
1252
1253 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1254 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001255 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1256 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001257
1258 __get_user(magic, &aux->fpsimd.head.magic);
1259 __get_user(size, &aux->fpsimd.head.size);
1260
1261 if (magic != TARGET_FPSIMD_MAGIC
1262 || size != sizeof(struct target_fpsimd_context)) {
1263 return 1;
1264 }
1265
Peter Maydell4cf23482014-03-02 19:36:38 +00001266 for (i = 0; i < 32; i++) {
1267#ifdef TARGET_WORDS_BIGENDIAN
1268 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1269 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1270#else
1271 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1272 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1273#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001274 }
Will Newtone0ee1382014-01-04 22:15:48 +00001275 __get_user(fpsr, &aux->fpsimd.fpsr);
1276 vfp_set_fpsr(env, fpsr);
1277 __get_user(fpcr, &aux->fpsimd.fpcr);
1278 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001279
1280 return 0;
1281}
1282
1283static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1284{
1285 abi_ulong sp;
1286
1287 sp = env->xregs[31];
1288
1289 /*
1290 * This is the X/Open sanctioned signal stack switching.
1291 */
Riku Voipiob545f632014-07-15 17:01:55 +03001292 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001293 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1294 }
1295
1296 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1297
1298 return sp;
1299}
1300
1301static void target_setup_frame(int usig, struct target_sigaction *ka,
1302 target_siginfo_t *info, target_sigset_t *set,
1303 CPUARMState *env)
1304{
1305 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001306 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001307
1308 frame_addr = get_sigframe(ka, env);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001309 trace_user_setup_frame(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001310 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1311 goto give_sigsegv;
1312 }
1313
1314 __put_user(0, &frame->uc.tuc_flags);
1315 __put_user(0, &frame->uc.tuc_link);
1316
1317 __put_user(target_sigaltstack_used.ss_sp,
1318 &frame->uc.tuc_stack.ss_sp);
1319 __put_user(sas_ss_flags(env->xregs[31]),
1320 &frame->uc.tuc_stack.ss_flags);
1321 __put_user(target_sigaltstack_used.ss_size,
1322 &frame->uc.tuc_stack.ss_size);
1323 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001324 if (ka->sa_flags & TARGET_SA_RESTORER) {
1325 return_addr = ka->sa_restorer;
1326 } else {
1327 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1328 __put_user(0xd2801168, &frame->tramp[0]);
1329 __put_user(0xd4000001, &frame->tramp[1]);
1330 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1331 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001332 env->xregs[0] = usig;
1333 env->xregs[31] = frame_addr;
1334 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1335 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001336 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001337 if (info) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00001338 tswap_siginfo(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001339 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1340 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1341 }
1342
1343 unlock_user_struct(frame, frame_addr, 1);
1344 return;
1345
1346 give_sigsegv:
1347 unlock_user_struct(frame, frame_addr, 1);
1348 force_sig(TARGET_SIGSEGV);
1349}
1350
1351static void setup_rt_frame(int sig, struct target_sigaction *ka,
1352 target_siginfo_t *info, target_sigset_t *set,
1353 CPUARMState *env)
1354{
1355 target_setup_frame(sig, ka, info, set, env);
1356}
1357
1358static void setup_frame(int sig, struct target_sigaction *ka,
1359 target_sigset_t *set, CPUARMState *env)
1360{
1361 target_setup_frame(sig, ka, 0, set, env);
1362}
1363
1364long do_rt_sigreturn(CPUARMState *env)
1365{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001366 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001367 abi_ulong frame_addr = env->xregs[31];
1368
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001369 trace_user_do_rt_sigreturn(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001370 if (frame_addr & 15) {
1371 goto badframe;
1372 }
1373
1374 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1375 goto badframe;
1376 }
1377
1378 if (target_restore_sigframe(env, frame)) {
1379 goto badframe;
1380 }
1381
1382 if (do_sigaltstack(frame_addr +
1383 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1384 0, get_sp_from_cpustate(env)) == -EFAULT) {
1385 goto badframe;
1386 }
1387
1388 unlock_user_struct(frame, frame_addr, 0);
1389 return env->xregs[0];
1390
1391 badframe:
1392 unlock_user_struct(frame, frame_addr, 0);
1393 force_sig(TARGET_SIGSEGV);
1394 return 0;
1395}
1396
1397long do_sigreturn(CPUARMState *env)
1398{
1399 return do_rt_sigreturn(env);
1400}
1401
bellard43fff232003-07-09 19:31:39 +00001402#elif defined(TARGET_ARM)
1403
1404struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001405 abi_ulong trap_no;
1406 abi_ulong error_code;
1407 abi_ulong oldmask;
1408 abi_ulong arm_r0;
1409 abi_ulong arm_r1;
1410 abi_ulong arm_r2;
1411 abi_ulong arm_r3;
1412 abi_ulong arm_r4;
1413 abi_ulong arm_r5;
1414 abi_ulong arm_r6;
1415 abi_ulong arm_r7;
1416 abi_ulong arm_r8;
1417 abi_ulong arm_r9;
1418 abi_ulong arm_r10;
1419 abi_ulong arm_fp;
1420 abi_ulong arm_ip;
1421 abi_ulong arm_sp;
1422 abi_ulong arm_lr;
1423 abi_ulong arm_pc;
1424 abi_ulong arm_cpsr;
1425 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001426};
1427
pbrooka745ec62008-05-06 15:36:17 +00001428struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001429 abi_ulong tuc_flags;
1430 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001431 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001432 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001433 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001434};
1435
pbrooka745ec62008-05-06 15:36:17 +00001436struct target_ucontext_v2 {
1437 abi_ulong tuc_flags;
1438 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001439 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001440 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001441 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001442 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001443 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1444};
1445
Peter Maydell0d871bd2010-11-24 15:20:05 +00001446struct target_user_vfp {
1447 uint64_t fpregs[32];
1448 abi_ulong fpscr;
1449};
1450
1451struct target_user_vfp_exc {
1452 abi_ulong fpexc;
1453 abi_ulong fpinst;
1454 abi_ulong fpinst2;
1455};
1456
1457struct target_vfp_sigframe {
1458 abi_ulong magic;
1459 abi_ulong size;
1460 struct target_user_vfp ufp;
1461 struct target_user_vfp_exc ufp_exc;
1462} __attribute__((__aligned__(8)));
1463
Peter Maydell08e11252010-11-24 15:20:07 +00001464struct target_iwmmxt_sigframe {
1465 abi_ulong magic;
1466 abi_ulong size;
1467 uint64_t regs[16];
1468 /* Note that not all the coprocessor control registers are stored here */
1469 uint32_t wcssf;
1470 uint32_t wcasf;
1471 uint32_t wcgr0;
1472 uint32_t wcgr1;
1473 uint32_t wcgr2;
1474 uint32_t wcgr3;
1475} __attribute__((__aligned__(8)));
1476
Peter Maydell0d871bd2010-11-24 15:20:05 +00001477#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001478#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001479
pbrooka8c33202008-05-07 23:22:46 +00001480struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001481{
1482 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001483 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1484 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001485};
1486
pbrooka8c33202008-05-07 23:22:46 +00001487struct sigframe_v2
1488{
1489 struct target_ucontext_v2 uc;
1490 abi_ulong retcode;
1491};
1492
pbrooka745ec62008-05-06 15:36:17 +00001493struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001494{
bellardf8b0aa22007-11-11 23:03:42 +00001495 abi_ulong pinfo;
1496 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001497 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001498 struct target_ucontext_v1 uc;
1499 abi_ulong retcode;
1500};
1501
1502struct rt_sigframe_v2
1503{
1504 struct target_siginfo info;
1505 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001506 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001507};
1508
1509#define TARGET_CONFIG_CPU_32 1
1510
1511/*
1512 * For ARM syscalls, we encode the syscall number into the instruction.
1513 */
1514#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1515#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1516
1517/*
1518 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1519 * need two 16-bit instructions.
1520 */
1521#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1522#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1523
blueswir1992f48a2007-10-14 16:27:31 +00001524static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001525 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1526 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1527};
1528
1529
Andreas Färber05390242012-02-25 03:37:53 +01001530static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001531{
1532 return 1;
1533}
1534
pbrooka8c33202008-05-07 23:22:46 +00001535static void
bellard43fff232003-07-09 19:31:39 +00001536setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001537 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001538{
pbrooka8c33202008-05-07 23:22:46 +00001539 __put_user(env->regs[0], &sc->arm_r0);
1540 __put_user(env->regs[1], &sc->arm_r1);
1541 __put_user(env->regs[2], &sc->arm_r2);
1542 __put_user(env->regs[3], &sc->arm_r3);
1543 __put_user(env->regs[4], &sc->arm_r4);
1544 __put_user(env->regs[5], &sc->arm_r5);
1545 __put_user(env->regs[6], &sc->arm_r6);
1546 __put_user(env->regs[7], &sc->arm_r7);
1547 __put_user(env->regs[8], &sc->arm_r8);
1548 __put_user(env->regs[9], &sc->arm_r9);
1549 __put_user(env->regs[10], &sc->arm_r10);
1550 __put_user(env->regs[11], &sc->arm_fp);
1551 __put_user(env->regs[12], &sc->arm_ip);
1552 __put_user(env->regs[13], &sc->arm_sp);
1553 __put_user(env->regs[14], &sc->arm_lr);
1554 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001555#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001556 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001557#endif
1558
pbrooka8c33202008-05-07 23:22:46 +00001559 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1560 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1561 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1562 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001563}
1564
bellard579a97f2007-11-11 14:26:47 +00001565static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001566get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001567{
1568 unsigned long sp = regs->regs[13];
1569
bellard43fff232003-07-09 19:31:39 +00001570 /*
1571 * This is the X/Open sanctioned signal stack switching.
1572 */
pbrook624f7972008-05-31 16:11:38 +00001573 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001574 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001575 /*
1576 * ATPCS B01 mandates 8-byte alignment
1577 */
bellard579a97f2007-11-11 14:26:47 +00001578 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001579}
1580
Riku Voipio0188fad2014-04-23 13:34:15 +03001581static void
Andreas Färber05390242012-02-25 03:37:53 +01001582setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001583 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001584{
pbrook624f7972008-05-31 16:11:38 +00001585 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001586 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001587 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001588 uint32_t cpsr = cpsr_read(env);
1589
1590 cpsr &= ~CPSR_IT;
1591 if (thumb) {
1592 cpsr |= CPSR_T;
1593 } else {
1594 cpsr &= ~CPSR_T;
1595 }
bellard43fff232003-07-09 19:31:39 +00001596
pbrook624f7972008-05-31 16:11:38 +00001597 if (ka->sa_flags & TARGET_SA_RESTORER) {
1598 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001599 } else {
1600 unsigned int idx = thumb;
1601
pbrook624f7972008-05-31 16:11:38 +00001602 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001603 idx += 2;
1604
Riku Voipio0188fad2014-04-23 13:34:15 +03001605 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001606
bellardf8b0aa22007-11-11 23:03:42 +00001607 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001608 }
1609
1610 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001611 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001612 env->regs[14] = retcode;
1613 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydellae087922016-02-23 15:36:43 +00001614 cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001615}
1616
Andreas Färber05390242012-02-25 03:37:53 +01001617static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001618{
1619 int i;
1620 struct target_vfp_sigframe *vfpframe;
1621 vfpframe = (struct target_vfp_sigframe *)regspace;
1622 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1623 __put_user(sizeof(*vfpframe), &vfpframe->size);
1624 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001625 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001626 }
1627 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1628 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1629 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1630 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1631 return (abi_ulong*)(vfpframe+1);
1632}
1633
Andreas Färber05390242012-02-25 03:37:53 +01001634static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1635 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001636{
1637 int i;
1638 struct target_iwmmxt_sigframe *iwmmxtframe;
1639 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1640 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1641 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1642 for (i = 0; i < 16; i++) {
1643 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1644 }
1645 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1646 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1647 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1648 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1649 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1650 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1651 return (abi_ulong*)(iwmmxtframe+1);
1652}
1653
pbrooka8c33202008-05-07 23:22:46 +00001654static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001655 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001656{
pbrooka8c33202008-05-07 23:22:46 +00001657 struct target_sigaltstack stack;
1658 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001659 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001660
1661 /* Clear all the bits of the ucontext we don't use. */
1662 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1663
1664 memset(&stack, 0, sizeof(stack));
1665 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1666 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1667 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1668 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1669
1670 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001671 /* Save coprocessor signal frame. */
1672 regspace = uc->tuc_regspace;
1673 if (arm_feature(env, ARM_FEATURE_VFP)) {
1674 regspace = setup_sigframe_v2_vfp(regspace, env);
1675 }
Peter Maydell08e11252010-11-24 15:20:07 +00001676 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1677 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1678 }
1679
Peter Maydell0d871bd2010-11-24 15:20:05 +00001680 /* Write terminating magic word */
1681 __put_user(0, regspace);
1682
pbrooka8c33202008-05-07 23:22:46 +00001683 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1684 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1685 }
1686}
1687
1688/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001689static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001690 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001691{
1692 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001693 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001694 int i;
bellard43fff232003-07-09 19:31:39 +00001695
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001696 trace_user_setup_frame(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001697 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1698 return;
1699
pbrooka8c33202008-05-07 23:22:46 +00001700 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001701
Riku Voipio0188fad2014-04-23 13:34:15 +03001702 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1703 __put_user(set->sig[i], &frame->extramask[i - 1]);
1704 }
bellard43fff232003-07-09 19:31:39 +00001705
pbrooka8c33202008-05-07 23:22:46 +00001706 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1707 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001708
bellard579a97f2007-11-11 14:26:47 +00001709 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001710}
1711
pbrook624f7972008-05-31 16:11:38 +00001712static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001713 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001714{
1715 struct sigframe_v2 *frame;
1716 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1717
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001718 trace_user_setup_frame(regs, frame_addr);
pbrooka8c33202008-05-07 23:22:46 +00001719 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1720 return;
1721
1722 setup_sigframe_v2(&frame->uc, set, regs);
1723
1724 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1725 frame_addr + offsetof(struct sigframe_v2, retcode));
1726
1727 unlock_user_struct(frame, frame_addr, 1);
1728}
1729
pbrook624f7972008-05-31 16:11:38 +00001730static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001731 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001732{
1733 if (get_osversion() >= 0x020612) {
1734 setup_frame_v2(usig, ka, set, regs);
1735 } else {
1736 setup_frame_v1(usig, ka, set, regs);
1737 }
bellard43fff232003-07-09 19:31:39 +00001738}
1739
bellard579a97f2007-11-11 14:26:47 +00001740/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001741static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001742 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001743 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001744{
pbrooka745ec62008-05-06 15:36:17 +00001745 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001746 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001747 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001748 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001749 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001750
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001751 trace_user_setup_rt_frame(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001752 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001753 return /* 1 */;
1754
pbrooka745ec62008-05-06 15:36:17 +00001755 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001756 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001757 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001758 __put_user(uc_addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001759 tswap_siginfo(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001760
1761 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001762 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001763
thsa04e1342007-09-27 13:57:58 +00001764 memset(&stack, 0, sizeof(stack));
1765 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1766 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1767 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001768 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001769
pbrooka8c33202008-05-07 23:22:46 +00001770 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001771 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03001772 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
bellard92319442004-06-19 16:58:13 +00001773 }
bellard43fff232003-07-09 19:31:39 +00001774
pbrooka8c33202008-05-07 23:22:46 +00001775 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1776 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001777
pbrooka8c33202008-05-07 23:22:46 +00001778 env->regs[1] = info_addr;
1779 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001780
pbrooka745ec62008-05-06 15:36:17 +00001781 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001782}
1783
pbrook624f7972008-05-31 16:11:38 +00001784static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001785 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001786 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001787{
1788 struct rt_sigframe_v2 *frame;
1789 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001790 abi_ulong info_addr, uc_addr;
1791
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001792 trace_user_setup_rt_frame(env, frame_addr);
pbrooka745ec62008-05-06 15:36:17 +00001793 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1794 return /* 1 */;
1795
1796 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1797 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001798 tswap_siginfo(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001799
pbrooka8c33202008-05-07 23:22:46 +00001800 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001801
pbrooka8c33202008-05-07 23:22:46 +00001802 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1803 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001804
pbrooka8c33202008-05-07 23:22:46 +00001805 env->regs[1] = info_addr;
1806 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001807
bellard579a97f2007-11-11 14:26:47 +00001808 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001809}
1810
pbrook624f7972008-05-31 16:11:38 +00001811static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001812 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001813 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001814{
1815 if (get_osversion() >= 0x020612) {
1816 setup_rt_frame_v2(usig, ka, info, set, env);
1817 } else {
1818 setup_rt_frame_v1(usig, ka, info, set, env);
1819 }
1820}
1821
bellard43fff232003-07-09 19:31:39 +00001822static int
Andreas Färber05390242012-02-25 03:37:53 +01001823restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001824{
1825 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001826 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001827
Riku Voipio1d8b5122014-04-23 10:26:05 +03001828 __get_user(env->regs[0], &sc->arm_r0);
1829 __get_user(env->regs[1], &sc->arm_r1);
1830 __get_user(env->regs[2], &sc->arm_r2);
1831 __get_user(env->regs[3], &sc->arm_r3);
1832 __get_user(env->regs[4], &sc->arm_r4);
1833 __get_user(env->regs[5], &sc->arm_r5);
1834 __get_user(env->regs[6], &sc->arm_r6);
1835 __get_user(env->regs[7], &sc->arm_r7);
1836 __get_user(env->regs[8], &sc->arm_r8);
1837 __get_user(env->regs[9], &sc->arm_r9);
1838 __get_user(env->regs[10], &sc->arm_r10);
1839 __get_user(env->regs[11], &sc->arm_fp);
1840 __get_user(env->regs[12], &sc->arm_ip);
1841 __get_user(env->regs[13], &sc->arm_sp);
1842 __get_user(env->regs[14], &sc->arm_lr);
1843 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001844#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001845 __get_user(cpsr, &sc->arm_cpsr);
Peter Maydell50866ba2016-02-23 15:36:43 +00001846 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001847#endif
1848
1849 err |= !valid_user_regs(env);
1850
1851 return err;
1852}
1853
Andreas Färber05390242012-02-25 03:37:53 +01001854static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001855{
bellardf8b0aa22007-11-11 23:03:42 +00001856 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001857 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001858 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001859 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001860 int i;
bellard43fff232003-07-09 19:31:39 +00001861
1862 /*
1863 * Since we stacked the signal on a 64-bit boundary,
1864 * then 'sp' should be word aligned here. If it's
1865 * not, then the user is trying to mess with us.
1866 */
bellardf8b0aa22007-11-11 23:03:42 +00001867 frame_addr = env->regs[13];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001868 trace_user_do_sigreturn(env, frame_addr);
Peter Maydell978fae92013-07-29 12:00:32 +01001869 if (frame_addr & 7) {
1870 goto badframe;
1871 }
1872
bellardf8b0aa22007-11-11 23:03:42 +00001873 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1874 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001875
Riku Voipiof5f601a2014-04-23 13:00:17 +03001876 __get_user(set.sig[0], &frame->sc.oldmask);
1877 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1878 __get_user(set.sig[i], &frame->extramask[i - 1]);
1879 }
bellard43fff232003-07-09 19:31:39 +00001880
bellard92319442004-06-19 16:58:13 +00001881 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001882 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001883
1884 if (restore_sigcontext(env, &frame->sc))
1885 goto badframe;
1886
1887#if 0
1888 /* Send SIGTRAP if we're single-stepping */
1889 if (ptrace_cancel_bpt(current))
1890 send_sig(SIGTRAP, current, 1);
1891#endif
bellardf8b0aa22007-11-11 23:03:42 +00001892 unlock_user_struct(frame, frame_addr, 0);
1893 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001894
1895badframe:
Riku Voipio66393fb2009-12-04 15:16:32 +02001896 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001897 return 0;
1898}
1899
Andreas Färber05390242012-02-25 03:37:53 +01001900static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001901{
1902 int i;
1903 abi_ulong magic, sz;
1904 uint32_t fpscr, fpexc;
1905 struct target_vfp_sigframe *vfpframe;
1906 vfpframe = (struct target_vfp_sigframe *)regspace;
1907
1908 __get_user(magic, &vfpframe->magic);
1909 __get_user(sz, &vfpframe->size);
1910 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1911 return 0;
1912 }
1913 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001914 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001915 }
1916 __get_user(fpscr, &vfpframe->ufp.fpscr);
1917 vfp_set_fpscr(env, fpscr);
1918 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1919 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1920 * and the exception flag is cleared
1921 */
1922 fpexc |= (1 << 30);
1923 fpexc &= ~((1 << 31) | (1 << 28));
1924 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1925 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1926 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1927 return (abi_ulong*)(vfpframe + 1);
1928}
1929
Andreas Färber05390242012-02-25 03:37:53 +01001930static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1931 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001932{
1933 int i;
1934 abi_ulong magic, sz;
1935 struct target_iwmmxt_sigframe *iwmmxtframe;
1936 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1937
1938 __get_user(magic, &iwmmxtframe->magic);
1939 __get_user(sz, &iwmmxtframe->size);
1940 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1941 return 0;
1942 }
1943 for (i = 0; i < 16; i++) {
1944 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1945 }
1946 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1947 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1948 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1949 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1950 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1951 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1952 return (abi_ulong*)(iwmmxtframe + 1);
1953}
1954
Andreas Färber05390242012-02-25 03:37:53 +01001955static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001956 struct target_ucontext_v2 *uc)
1957{
1958 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001959 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001960
1961 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001962 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001963
1964 if (restore_sigcontext(env, &uc->tuc_mcontext))
1965 return 1;
1966
Peter Maydell5f9099d2010-11-24 15:20:06 +00001967 /* Restore coprocessor signal frame */
1968 regspace = uc->tuc_regspace;
1969 if (arm_feature(env, ARM_FEATURE_VFP)) {
1970 regspace = restore_sigframe_v2_vfp(env, regspace);
1971 if (!regspace) {
1972 return 1;
1973 }
1974 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001975 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1976 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1977 if (!regspace) {
1978 return 1;
1979 }
1980 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001981
pbrooka8c33202008-05-07 23:22:46 +00001982 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1983 return 1;
1984
1985#if 0
1986 /* Send SIGTRAP if we're single-stepping */
1987 if (ptrace_cancel_bpt(current))
1988 send_sig(SIGTRAP, current, 1);
1989#endif
1990
1991 return 0;
1992}
1993
Andreas Färber05390242012-02-25 03:37:53 +01001994static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001995{
1996 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001997 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00001998
1999 /*
2000 * Since we stacked the signal on a 64-bit boundary,
2001 * then 'sp' should be word aligned here. If it's
2002 * not, then the user is trying to mess with us.
2003 */
pbrooka8c33202008-05-07 23:22:46 +00002004 frame_addr = env->regs[13];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002005 trace_user_do_sigreturn(env, frame_addr);
Peter Maydell978fae92013-07-29 12:00:32 +01002006 if (frame_addr & 7) {
2007 goto badframe;
2008 }
2009
pbrooka8c33202008-05-07 23:22:46 +00002010 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2011 goto badframe;
2012
2013 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2014 goto badframe;
2015
2016 unlock_user_struct(frame, frame_addr, 0);
2017 return env->regs[0];
2018
2019badframe:
2020 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002021 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002022 return 0;
2023}
2024
Andreas Färber05390242012-02-25 03:37:53 +01002025long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002026{
2027 if (get_osversion() >= 0x020612) {
2028 return do_sigreturn_v2(env);
2029 } else {
2030 return do_sigreturn_v1(env);
2031 }
2032}
2033
Andreas Färber05390242012-02-25 03:37:53 +01002034static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002035{
bellardf8b0aa22007-11-11 23:03:42 +00002036 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002037 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002038 sigset_t host_set;
2039
2040 /*
2041 * Since we stacked the signal on a 64-bit boundary,
2042 * then 'sp' should be word aligned here. If it's
2043 * not, then the user is trying to mess with us.
2044 */
bellardf8b0aa22007-11-11 23:03:42 +00002045 frame_addr = env->regs[13];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002046 trace_user_do_rt_sigreturn(env, frame_addr);
Peter Maydell978fae92013-07-29 12:00:32 +01002047 if (frame_addr & 7) {
2048 goto badframe;
2049 }
2050
bellardf8b0aa22007-11-11 23:03:42 +00002051 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2052 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002053
bellardb8076a72005-04-07 22:20:31 +00002054 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002055 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002056
bellardb8076a72005-04-07 22:20:31 +00002057 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002058 goto badframe;
2059
pbrooka745ec62008-05-06 15:36:17 +00002060 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 +00002061 goto badframe;
2062
bellard43fff232003-07-09 19:31:39 +00002063#if 0
2064 /* Send SIGTRAP if we're single-stepping */
2065 if (ptrace_cancel_bpt(current))
2066 send_sig(SIGTRAP, current, 1);
2067#endif
bellardf8b0aa22007-11-11 23:03:42 +00002068 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002069 return env->regs[0];
2070
2071badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002072 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002073 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002074 return 0;
2075}
2076
Andreas Färber05390242012-02-25 03:37:53 +01002077static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002078{
2079 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002080 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002081
2082 /*
2083 * Since we stacked the signal on a 64-bit boundary,
2084 * then 'sp' should be word aligned here. If it's
2085 * not, then the user is trying to mess with us.
2086 */
pbrooka745ec62008-05-06 15:36:17 +00002087 frame_addr = env->regs[13];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002088 trace_user_do_rt_sigreturn(env, frame_addr);
Peter Maydell978fae92013-07-29 12:00:32 +01002089 if (frame_addr & 7) {
2090 goto badframe;
2091 }
2092
pbrooka745ec62008-05-06 15:36:17 +00002093 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2094 goto badframe;
2095
pbrooka8c33202008-05-07 23:22:46 +00002096 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2097 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002098
pbrooka745ec62008-05-06 15:36:17 +00002099 unlock_user_struct(frame, frame_addr, 0);
2100 return env->regs[0];
2101
2102badframe:
2103 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002104 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002105 return 0;
2106}
2107
Andreas Färber05390242012-02-25 03:37:53 +01002108long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002109{
2110 if (get_osversion() >= 0x020612) {
2111 return do_rt_sigreturn_v2(env);
2112 } else {
2113 return do_rt_sigreturn_v1(env);
2114 }
2115}
2116
bellard6d5e2162004-09-30 22:04:13 +00002117#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002118
bellard6d5e2162004-09-30 22:04:13 +00002119#define __SUNOS_MAXWIN 31
2120
2121/* This is what SunOS does, so shall I. */
2122struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002123 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002124
blueswir1992f48a2007-10-14 16:27:31 +00002125 abi_ulong sigc_mask; /* sigmask to restore */
2126 abi_ulong sigc_sp; /* stack pointer */
2127 abi_ulong sigc_pc; /* program counter */
2128 abi_ulong sigc_npc; /* next program counter */
2129 abi_ulong sigc_psr; /* for condition codes etc */
2130 abi_ulong sigc_g1; /* User uses these two registers */
2131 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002132
2133 /* Now comes information regarding the users window set
2134 * at the time of the signal.
2135 */
blueswir1992f48a2007-10-14 16:27:31 +00002136 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002137
2138 /* stack ptrs for each regwin buf */
2139 char *sigc_spbuf[__SUNOS_MAXWIN];
2140
2141 /* Windows to restore after signal */
2142 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002143 abi_ulong locals[8];
2144 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002145 } sigc_wbuf[__SUNOS_MAXWIN];
2146};
2147/* A Sparc stack frame */
2148struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002149 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002150 abi_ulong ins[8];
2151 /* It's simpler to treat fp and callers_pc as elements of ins[]
2152 * since we never need to access them ourselves.
2153 */
bellard6d5e2162004-09-30 22:04:13 +00002154 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002155 abi_ulong xargs[6];
2156 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002157};
2158
2159typedef struct {
2160 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002161 abi_ulong psr;
2162 abi_ulong pc;
2163 abi_ulong npc;
2164 abi_ulong y;
2165 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002166 } si_regs;
2167 int si_mask;
2168} __siginfo_t;
2169
2170typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002171 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002172 unsigned long si_fsr;
2173 unsigned long si_fpqdepth;
2174 struct {
2175 unsigned long *insn_addr;
2176 unsigned long insn;
2177 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002178} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002179
2180
2181struct target_signal_frame {
2182 struct sparc_stackf ss;
2183 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002184 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002185 abi_ulong insns[2] __attribute__ ((aligned (8)));
2186 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2187 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002188 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002189};
2190struct target_rt_signal_frame {
2191 struct sparc_stackf ss;
2192 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002193 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002194 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002195 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002196 unsigned int insns[2];
2197 stack_t stack;
2198 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002199 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002200};
2201
bellarde80cfcf2004-12-19 23:18:01 +00002202#define UREG_O0 16
2203#define UREG_O6 22
2204#define UREG_I0 0
2205#define UREG_I1 1
2206#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002207#define UREG_I3 3
2208#define UREG_I4 4
2209#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002210#define UREG_I6 6
2211#define UREG_I7 7
2212#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002213#define UREG_FP UREG_I6
2214#define UREG_SP UREG_O6
2215
pbrook624f7972008-05-31 16:11:38 +00002216static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002217 CPUSPARCState *env,
2218 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002219{
bellard459a4012007-11-11 19:45:10 +00002220 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002221
2222 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002223
2224 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002225 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002226 if (!on_sig_stack(sp)
2227 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2228 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002229 }
bellard459a4012007-11-11 19:45:10 +00002230 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002231}
2232
2233static int
Andreas Färber05390242012-02-25 03:37:53 +01002234setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002235{
2236 int err = 0, i;
2237
Riku Voipio1d8b5122014-04-23 10:26:05 +03002238 __put_user(env->psr, &si->si_regs.psr);
2239 __put_user(env->pc, &si->si_regs.pc);
2240 __put_user(env->npc, &si->si_regs.npc);
2241 __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002242 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002243 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
bellard6d5e2162004-09-30 22:04:13 +00002244 }
bellarda315a142005-01-30 22:59:18 +00002245 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002246 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002247 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002248 __put_user(mask, &si->si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002249 return err;
2250}
bellarde80cfcf2004-12-19 23:18:01 +00002251
bellard80a9d032005-01-03 23:31:27 +00002252#if 0
bellard6d5e2162004-09-30 22:04:13 +00002253static int
2254setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002255 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002256{
2257 int err = 0;
2258
Riku Voipio1d8b5122014-04-23 10:26:05 +03002259 __put_user(mask, &sc->sigc_mask);
2260 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2261 __put_user(env->pc, &sc->sigc_pc);
2262 __put_user(env->npc, &sc->sigc_npc);
2263 __put_user(env->psr, &sc->sigc_psr);
2264 __put_user(env->gregs[1], &sc->sigc_g1);
2265 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002266
2267 return err;
2268}
bellard80a9d032005-01-03 23:31:27 +00002269#endif
bellard6d5e2162004-09-30 22:04:13 +00002270#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2271
pbrook624f7972008-05-31 16:11:38 +00002272static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002273 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002274{
bellard459a4012007-11-11 19:45:10 +00002275 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002276 struct target_signal_frame *sf;
2277 int sigframe_size, err, i;
2278
2279 /* 1. Make sure everything is clean */
2280 //synchronize_user_stack();
2281
2282 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002283 sf_addr = get_sigframe(ka, env, sigframe_size);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002284 trace_user_setup_frame(env, sf_addr);
bellard6d5e2162004-09-30 22:04:13 +00002285
bellard459a4012007-11-11 19:45:10 +00002286 sf = lock_user(VERIFY_WRITE, sf_addr,
2287 sizeof(struct target_signal_frame), 0);
2288 if (!sf)
2289 goto sigsegv;
2290
bellard6d5e2162004-09-30 22:04:13 +00002291#if 0
2292 if (invalid_frame_pointer(sf, sigframe_size))
2293 goto sigill_and_return;
2294#endif
2295 /* 2. Save the current process state */
2296 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002297 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002298
Riku Voipio1d8b5122014-04-23 10:26:05 +03002299 //save_fpu_state(regs, &sf->fpu_state);
2300 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002301
Riku Voipio1d8b5122014-04-23 10:26:05 +03002302 __put_user(set->sig[0], &sf->info.si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002303 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002304 __put_user(set->sig[i + 1], &sf->extramask[i]);
bellard6d5e2162004-09-30 22:04:13 +00002305 }
2306
bellarda315a142005-01-30 22:59:18 +00002307 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002308 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002309 }
bellarda315a142005-01-30 22:59:18 +00002310 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002311 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002312 }
bellard6d5e2162004-09-30 22:04:13 +00002313 if (err)
2314 goto sigsegv;
2315
2316 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002317 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002318 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002319 env->regwptr[UREG_I1] = sf_addr +
2320 offsetof(struct target_signal_frame, info);
2321 env->regwptr[UREG_I2] = sf_addr +
2322 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002323
2324 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002325 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002326 env->npc = (env->pc + 4);
2327 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002328 if (ka->sa_restorer)
2329 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002330 else {
bellard775b58d2007-11-11 16:22:17 +00002331 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002332
2333 env->regwptr[UREG_I7] = sf_addr +
2334 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002335
2336 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002337 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002338 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002339
2340 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002341 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002342 __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002343 if (err)
2344 goto sigsegv;
2345
2346 /* Flush instruction space. */
2347 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
Peter Crosthwaitebbd77c12015-06-23 19:31:15 -07002348 // tb_flush(CPU(sparc_env_get_cpu(env)));
bellard6d5e2162004-09-30 22:04:13 +00002349 }
bellard459a4012007-11-11 19:45:10 +00002350 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002351 return;
bellard459a4012007-11-11 19:45:10 +00002352#if 0
2353sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002354 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002355#endif
bellard6d5e2162004-09-30 22:04:13 +00002356sigsegv:
bellard459a4012007-11-11 19:45:10 +00002357 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002358 force_sig(TARGET_SIGSEGV);
2359}
bellard6d5e2162004-09-30 22:04:13 +00002360
pbrook624f7972008-05-31 16:11:38 +00002361static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002362 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002363 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002364{
2365 fprintf(stderr, "setup_rt_frame: not implemented\n");
2366}
2367
Andreas Färber05390242012-02-25 03:37:53 +01002368long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002369{
bellardf8b0aa22007-11-11 23:03:42 +00002370 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002371 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002372 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002373 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002374 sigset_t host_set;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002375 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002376
bellardf8b0aa22007-11-11 23:03:42 +00002377 sf_addr = env->regwptr[UREG_FP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002378 trace_user_do_sigreturn(env, sf_addr);
bellardf8b0aa22007-11-11 23:03:42 +00002379 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2380 goto segv_and_exit;
bellard6d5e2162004-09-30 22:04:13 +00002381
2382 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002383
bellardf8b0aa22007-11-11 23:03:42 +00002384 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002385 goto segv_and_exit;
2386
Riku Voipio1d8b5122014-04-23 10:26:05 +03002387 __get_user(pc, &sf->info.si_regs.pc);
2388 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002389
bellard6d5e2162004-09-30 22:04:13 +00002390 if ((pc | npc) & 3)
2391 goto segv_and_exit;
2392
2393 /* 2. Restore the state */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002394 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002395
bellard6d5e2162004-09-30 22:04:13 +00002396 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002397 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2398 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2399
2400 env->pc = pc;
2401 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002402 __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002403 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002404 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
bellarde80cfcf2004-12-19 23:18:01 +00002405 }
bellarda315a142005-01-30 22:59:18 +00002406 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002407 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
bellarde80cfcf2004-12-19 23:18:01 +00002408 }
bellard6d5e2162004-09-30 22:04:13 +00002409
Peter Maydell2aec3a22011-06-16 17:37:14 +01002410 /* FIXME: implement FPU save/restore:
2411 * __get_user(fpu_save, &sf->fpu_save);
2412 * if (fpu_save)
2413 * err |= restore_fpu_state(env, fpu_save);
2414 */
bellard6d5e2162004-09-30 22:04:13 +00002415
2416 /* This is pretty much atomic, no amount locking would prevent
2417 * the races which exist anyways.
2418 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002419 __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002420 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002421 __get_user(set.sig[i], &sf->extramask[i - 1]);
bellarde80cfcf2004-12-19 23:18:01 +00002422 }
2423
2424 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002425 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002426
2427 if (err)
2428 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002429 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002430 return env->regwptr[0];
2431
2432segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002433 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002434 force_sig(TARGET_SIGSEGV);
2435}
2436
Andreas Färber05390242012-02-25 03:37:53 +01002437long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002438{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002439 trace_user_do_rt_sigreturn(env, 0);
bellard6d5e2162004-09-30 22:04:13 +00002440 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002441 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002442}
2443
bellard459a4012007-11-11 19:45:10 +00002444#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002445#define MC_TSTATE 0
2446#define MC_PC 1
2447#define MC_NPC 2
2448#define MC_Y 3
2449#define MC_G1 4
2450#define MC_G2 5
2451#define MC_G3 6
2452#define MC_G4 7
2453#define MC_G5 8
2454#define MC_G6 9
2455#define MC_G7 10
2456#define MC_O0 11
2457#define MC_O1 12
2458#define MC_O2 13
2459#define MC_O3 14
2460#define MC_O4 15
2461#define MC_O5 16
2462#define MC_O6 17
2463#define MC_O7 18
2464#define MC_NGREG 19
2465
Anthony Liguoric227f092009-10-01 16:12:16 -05002466typedef abi_ulong target_mc_greg_t;
2467typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002468
2469struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002470 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002471 uint32_t mcfq_insn;
2472};
2473
2474struct target_mc_fpu {
2475 union {
2476 uint32_t sregs[32];
2477 uint64_t dregs[32];
2478 //uint128_t qregs[16];
2479 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002480 abi_ulong mcfpu_fsr;
2481 abi_ulong mcfpu_fprs;
2482 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002483 struct target_mc_fq *mcfpu_fq;
2484 unsigned char mcfpu_qcnt;
2485 unsigned char mcfpu_qentsz;
2486 unsigned char mcfpu_enab;
2487};
Anthony Liguoric227f092009-10-01 16:12:16 -05002488typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002489
2490typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002491 target_mc_gregset_t mc_gregs;
2492 target_mc_greg_t mc_fp;
2493 target_mc_greg_t mc_i7;
2494 target_mc_fpu_t mc_fpregs;
2495} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002496
2497struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002498 struct target_ucontext *tuc_link;
2499 abi_ulong tuc_flags;
2500 target_sigset_t tuc_sigmask;
2501 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002502};
2503
2504/* A V9 register window */
2505struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002506 abi_ulong locals[8];
2507 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002508};
2509
2510#define TARGET_STACK_BIAS 2047
2511
2512/* {set, get}context() needed for 64-bit SparcLinux userland. */
2513void sparc64_set_context(CPUSPARCState *env)
2514{
bellard459a4012007-11-11 19:45:10 +00002515 abi_ulong ucp_addr;
2516 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002517 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002518 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002519 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002520 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002521
bellard459a4012007-11-11 19:45:10 +00002522 ucp_addr = env->regwptr[UREG_I0];
2523 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2524 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002525 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002526 __get_user(pc, &((*grp)[MC_PC]));
2527 __get_user(npc, &((*grp)[MC_NPC]));
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002528 if ((pc | npc) & 3)
blueswir15bfb56b2007-10-05 17:01:51 +00002529 goto do_sigsegv;
2530 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002531 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002532 sigset_t set;
2533
2534 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002535 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002536 } else {
bellard459a4012007-11-11 19:45:10 +00002537 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002538 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002539 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002540 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002541 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002542 }
blueswir15bfb56b2007-10-05 17:01:51 +00002543 }
2544 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002545 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002546 }
2547 env->pc = pc;
2548 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002549 __get_user(env->y, &((*grp)[MC_Y]));
2550 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002551 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002552 cpu_put_ccr(env, tstate >> 32);
2553 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002554 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2555 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2556 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2557 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2558 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2559 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2560 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2561 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2562 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2563 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2564 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2565 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2566 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2567 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2568 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002569
Riku Voipio1d8b5122014-04-23 10:26:05 +03002570 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2571 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002572
bellard459a4012007-11-11 19:45:10 +00002573 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2574 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2575 abi_ulong) != 0)
2576 goto do_sigsegv;
2577 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2578 abi_ulong) != 0)
2579 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002580 /* FIXME this does not match how the kernel handles the FPU in
2581 * its sparc64_set_context implementation. In particular the FPU
2582 * is only restored if fenab is non-zero in:
2583 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2584 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002585 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002586 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002587 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2588 for (i = 0; i < 64; i++, src++) {
2589 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002590 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002591 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002592 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002593 }
2594 }
bellard459a4012007-11-11 19:45:10 +00002595 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002596 __get_user(env->fsr,
2597 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2598 __get_user(env->gsr,
2599 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002600 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002601 return;
2602 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002603 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002604 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002605}
2606
2607void sparc64_get_context(CPUSPARCState *env)
2608{
bellard459a4012007-11-11 19:45:10 +00002609 abi_ulong ucp_addr;
2610 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002611 target_mc_gregset_t *grp;
2612 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002613 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002614 int err;
2615 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002616 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002617 sigset_t set;
2618
bellard459a4012007-11-11 19:45:10 +00002619 ucp_addr = env->regwptr[UREG_I0];
2620 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2621 goto do_sigsegv;
2622
Aurelien Jarno60e99242010-03-29 02:12:51 +02002623 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002624 grp = &mcp->mc_gregs;
2625
2626 /* Skip over the trap instruction, first. */
2627 env->pc = env->npc;
2628 env->npc += 4;
2629
2630 err = 0;
2631
Alex Barcelo1c275922014-03-14 14:36:55 +00002632 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002633 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002634 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002635 __put_user(target_set.sig[0],
2636 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002637 } else {
2638 abi_ulong *src, *dst;
2639 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002640 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002641 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002642 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002643 }
blueswir15bfb56b2007-10-05 17:01:51 +00002644 if (err)
2645 goto do_sigsegv;
2646 }
2647
bellard459a4012007-11-11 19:45:10 +00002648 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002649 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2650 __put_user(env->pc, &((*grp)[MC_PC]));
2651 __put_user(env->npc, &((*grp)[MC_NPC]));
2652 __put_user(env->y, &((*grp)[MC_Y]));
2653 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2654 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2655 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2656 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2657 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2658 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2659 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2660 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2661 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2662 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2663 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2664 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2665 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2666 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2667 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002668
bellard459a4012007-11-11 19:45:10 +00002669 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2670 fp = i7 = 0;
2671 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2672 abi_ulong) != 0)
2673 goto do_sigsegv;
2674 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2675 abi_ulong) != 0)
2676 goto do_sigsegv;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002677 __put_user(fp, &(mcp->mc_fp));
2678 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002679
bellard459a4012007-11-11 19:45:10 +00002680 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002681 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2682 for (i = 0; i < 64; i++, dst++) {
2683 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002684 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002685 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002686 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002687 }
2688 }
bellard459a4012007-11-11 19:45:10 +00002689 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002690 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2691 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2692 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002693
2694 if (err)
2695 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002696 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002697 return;
2698 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002699 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002700 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002701}
2702#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002703#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002704
Richard Hendersonff970902013-02-10 10:30:42 -08002705# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002706struct target_sigcontext {
2707 uint32_t sc_regmask; /* Unused */
2708 uint32_t sc_status;
2709 uint64_t sc_pc;
2710 uint64_t sc_regs[32];
2711 uint64_t sc_fpregs[32];
2712 uint32_t sc_ownedfp; /* Unused */
2713 uint32_t sc_fpc_csr;
2714 uint32_t sc_fpc_eir; /* Unused */
2715 uint32_t sc_used_math;
2716 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002717 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002718 uint64_t sc_mdhi;
2719 uint64_t sc_mdlo;
2720 target_ulong sc_hi1; /* Was sc_cause */
2721 target_ulong sc_lo1; /* Was sc_badvaddr */
2722 target_ulong sc_hi2; /* Was sc_sigset[4] */
2723 target_ulong sc_lo2;
2724 target_ulong sc_hi3;
2725 target_ulong sc_lo3;
2726};
Richard Hendersonff970902013-02-10 10:30:42 -08002727# else /* N32 || N64 */
2728struct target_sigcontext {
2729 uint64_t sc_regs[32];
2730 uint64_t sc_fpregs[32];
2731 uint64_t sc_mdhi;
2732 uint64_t sc_hi1;
2733 uint64_t sc_hi2;
2734 uint64_t sc_hi3;
2735 uint64_t sc_mdlo;
2736 uint64_t sc_lo1;
2737 uint64_t sc_lo2;
2738 uint64_t sc_lo3;
2739 uint64_t sc_pc;
2740 uint32_t sc_fpc_csr;
2741 uint32_t sc_used_math;
2742 uint32_t sc_dsp;
2743 uint32_t sc_reserved;
2744};
2745# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002746
2747struct sigframe {
2748 uint32_t sf_ass[4]; /* argument save space for o32 */
2749 uint32_t sf_code[2]; /* signal trampoline */
2750 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002751 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002752};
2753
pbrook0b1bcb02009-04-21 01:41:10 +00002754struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002755 target_ulong tuc_flags;
2756 target_ulong tuc_link;
2757 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002758 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002759 struct target_sigcontext tuc_mcontext;
2760 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002761};
2762
2763struct target_rt_sigframe {
2764 uint32_t rs_ass[4]; /* argument save space for o32 */
2765 uint32_t rs_code[2]; /* signal trampoline */
2766 struct target_siginfo rs_info;
2767 struct target_ucontext rs_uc;
2768};
2769
bellard106ec872006-06-27 21:08:10 +00002770/* Install trampoline to jump back from signal handler */
2771static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2772{
Richard Henderson084d0492013-02-10 10:30:44 -08002773 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002774
2775 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002776 * Set up the return code ...
2777 *
2778 * li v0, __NR__foo_sigreturn
2779 * syscall
2780 */
bellard106ec872006-06-27 21:08:10 +00002781
Riku Voipio1d8b5122014-04-23 10:26:05 +03002782 __put_user(0x24020000 + syscall, tramp + 0);
2783 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002784 return err;
2785}
2786
Riku Voipio41ecc722014-04-23 11:01:00 +03002787static inline void setup_sigcontext(CPUMIPSState *regs,
2788 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002789{
Richard Henderson084d0492013-02-10 10:30:44 -08002790 int i;
bellard106ec872006-06-27 21:08:10 +00002791
Riku Voipio1d8b5122014-04-23 10:26:05 +03002792 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002793 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002794
Richard Henderson084d0492013-02-10 10:30:44 -08002795 __put_user(0, &sc->sc_regs[0]);
2796 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002797 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002798 }
bellard106ec872006-06-27 21:08:10 +00002799
Riku Voipio1d8b5122014-04-23 10:26:05 +03002800 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2801 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002802
Richard Henderson084d0492013-02-10 10:30:44 -08002803 /* Rather than checking for dsp existence, always copy. The storage
2804 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002805 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2806 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2807 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2808 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2809 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2810 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002811 {
2812 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002813 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002814 }
Richard Henderson084d0492013-02-10 10:30:44 -08002815
Riku Voipio1d8b5122014-04-23 10:26:05 +03002816 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002817
2818 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002819 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002820 }
bellard106ec872006-06-27 21:08:10 +00002821}
2822
Riku Voipio016d2e12014-04-23 11:19:48 +03002823static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002824restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002825{
Richard Henderson084d0492013-02-10 10:30:44 -08002826 int i;
bellard106ec872006-06-27 21:08:10 +00002827
Riku Voipio1d8b5122014-04-23 10:26:05 +03002828 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002829
Riku Voipio1d8b5122014-04-23 10:26:05 +03002830 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2831 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002832
Richard Henderson084d0492013-02-10 10:30:44 -08002833 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002834 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002835 }
2836
Riku Voipio1d8b5122014-04-23 10:26:05 +03002837 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2838 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2839 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2840 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2841 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2842 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002843 {
2844 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002845 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002846 cpu_wrdsp(dsp, 0x3ff, regs);
2847 }
2848
2849 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002850 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002851 }
bellard106ec872006-06-27 21:08:10 +00002852}
Richard Hendersonff970902013-02-10 10:30:42 -08002853
bellard106ec872006-06-27 21:08:10 +00002854/*
2855 * Determine which stack to use..
2856 */
bellard579a97f2007-11-11 14:26:47 +00002857static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002858get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002859{
2860 unsigned long sp;
2861
2862 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002863 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002864
2865 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002866 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002867 * above the user stack, 16-bytes before the next lowest
2868 * 16 byte boundary. Try to avoid trashing it.
2869 */
2870 sp -= 32;
2871
bellard106ec872006-06-27 21:08:10 +00002872 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002873 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002874 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2875 }
bellard106ec872006-06-27 21:08:10 +00002876
bellard579a97f2007-11-11 14:26:47 +00002877 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002878}
2879
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002880static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2881{
2882 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2883 env->hflags &= ~MIPS_HFLAG_M16;
2884 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2885 env->active_tc.PC &= ~(target_ulong) 1;
2886 }
2887}
2888
Richard Hendersonff970902013-02-10 10:30:42 -08002889# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002890/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002891static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002892 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002893{
2894 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002895 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002896 int i;
2897
bellard579a97f2007-11-11 14:26:47 +00002898 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002899 trace_user_setup_frame(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00002900 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002901 goto give_sigsegv;
2902
2903 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2904
Riku Voipio41ecc722014-04-23 11:01:00 +03002905 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002906
2907 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03002908 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00002909 }
2910
2911 /*
2912 * Arguments to signal handler:
2913 *
2914 * a0 = signal number
2915 * a1 = 0 (should be cause)
2916 * a2 = pointer to struct sigcontext
2917 *
2918 * $25 and PC point to the signal handler, $29 points to the
2919 * struct sigframe.
2920 */
thsb5dc7732008-06-27 10:02:35 +00002921 regs->active_tc.gpr[ 4] = sig;
2922 regs->active_tc.gpr[ 5] = 0;
2923 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2924 regs->active_tc.gpr[29] = frame_addr;
2925 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002926 /* The original kernel code sets CP0_EPC to the handler
2927 * since it returns to userland using eret
2928 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002929 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002930 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002931 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002932 return;
2933
2934give_sigsegv:
2935 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002936}
2937
Andreas Färber05390242012-02-25 03:37:53 +01002938long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002939{
ths388bb212007-05-13 13:58:00 +00002940 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002941 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002942 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002943 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002944 int i;
bellard106ec872006-06-27 21:08:10 +00002945
thsb5dc7732008-06-27 10:02:35 +00002946 frame_addr = regs->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002947 trace_user_do_sigreturn(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00002948 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002949 goto badframe;
2950
ths388bb212007-05-13 13:58:00 +00002951 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03002952 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00002953 }
bellard106ec872006-06-27 21:08:10 +00002954
ths388bb212007-05-13 13:58:00 +00002955 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002956 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002957
Riku Voipio016d2e12014-04-23 11:19:48 +03002958 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002959
2960#if 0
ths388bb212007-05-13 13:58:00 +00002961 /*
2962 * Don't let your children do this ...
2963 */
2964 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002965 "move\t$29, %0\n\t"
2966 "j\tsyscall_exit"
2967 :/* no outputs */
2968 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002969 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002970#endif
ths3b46e622007-09-17 08:09:54 +00002971
thsb5dc7732008-06-27 10:02:35 +00002972 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002973 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00002974 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002975 * maybe a problem with nested signals ? */
2976 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00002977 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00002978
2979badframe:
ths388bb212007-05-13 13:58:00 +00002980 force_sig(TARGET_SIGSEGV/*, current*/);
2981 return 0;
bellard106ec872006-06-27 21:08:10 +00002982}
Richard Hendersonff970902013-02-10 10:30:42 -08002983# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002984
pbrook624f7972008-05-31 16:11:38 +00002985static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002986 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002987 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00002988{
pbrook0b1bcb02009-04-21 01:41:10 +00002989 struct target_rt_sigframe *frame;
2990 abi_ulong frame_addr;
2991 int i;
2992
2993 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002994 trace_user_setup_rt_frame(env, frame_addr);
pbrook0b1bcb02009-04-21 01:41:10 +00002995 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2996 goto give_sigsegv;
2997
2998 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
2999
Peter Maydellf6c7a052015-01-08 12:19:48 +00003000 tswap_siginfo(&frame->rs_info, info);
pbrook0b1bcb02009-04-21 01:41:10 +00003001
Aurelien Jarno60e99242010-03-29 02:12:51 +02003002 __put_user(0, &frame->rs_uc.tuc_flags);
3003 __put_user(0, &frame->rs_uc.tuc_link);
3004 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3005 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003006 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003007 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003008
Aurelien Jarno60e99242010-03-29 02:12:51 +02003009 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003010
3011 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003012 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003013 }
3014
3015 /*
3016 * Arguments to signal handler:
3017 *
3018 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003019 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003020 * a2 = pointer to struct ucontext
3021 *
3022 * $25 and PC point to the signal handler, $29 points to the
3023 * struct sigframe.
3024 */
3025 env->active_tc.gpr[ 4] = sig;
3026 env->active_tc.gpr[ 5] = frame_addr
3027 + offsetof(struct target_rt_sigframe, rs_info);
3028 env->active_tc.gpr[ 6] = frame_addr
3029 + offsetof(struct target_rt_sigframe, rs_uc);
3030 env->active_tc.gpr[29] = frame_addr;
3031 env->active_tc.gpr[31] = frame_addr
3032 + offsetof(struct target_rt_sigframe, rs_code);
3033 /* The original kernel code sets CP0_EPC to the handler
3034 * since it returns to userland using eret
3035 * we cannot do this here, and we must set PC directly */
3036 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003037 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003038 unlock_user_struct(frame, frame_addr, 1);
3039 return;
3040
3041give_sigsegv:
3042 unlock_user_struct(frame, frame_addr, 1);
3043 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003044}
3045
Andreas Färber05390242012-02-25 03:37:53 +01003046long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003047{
pbrook0b1bcb02009-04-21 01:41:10 +00003048 struct target_rt_sigframe *frame;
3049 abi_ulong frame_addr;
3050 sigset_t blocked;
3051
pbrook0b1bcb02009-04-21 01:41:10 +00003052 frame_addr = env->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003053 trace_user_do_rt_sigreturn(env, frame_addr);
pbrook0b1bcb02009-04-21 01:41:10 +00003054 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3055 goto badframe;
3056
Aurelien Jarno60e99242010-03-29 02:12:51 +02003057 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003058 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003059
Riku Voipio016d2e12014-04-23 11:19:48 +03003060 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003061
3062 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003063 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003064 0, get_sp_from_cpustate(env)) == -EFAULT)
3065 goto badframe;
3066
3067 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003068 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003069 /* I am not sure this is right, but it seems to work
3070 * maybe a problem with nested signals ? */
3071 env->CP0_EPC = 0;
3072 return -TARGET_QEMU_ESIGRETURN;
3073
3074badframe:
3075 force_sig(TARGET_SIGSEGV/*, current*/);
3076 return 0;
bellard106ec872006-06-27 21:08:10 +00003077}
bellard6d5e2162004-09-30 22:04:13 +00003078
thsc3b5bc82007-12-02 06:31:25 +00003079#elif defined(TARGET_SH4)
3080
3081/*
3082 * code and data structures from linux kernel:
3083 * include/asm-sh/sigcontext.h
3084 * arch/sh/kernel/signal.c
3085 */
3086
3087struct target_sigcontext {
3088 target_ulong oldmask;
3089
3090 /* CPU registers */
3091 target_ulong sc_gregs[16];
3092 target_ulong sc_pc;
3093 target_ulong sc_pr;
3094 target_ulong sc_sr;
3095 target_ulong sc_gbr;
3096 target_ulong sc_mach;
3097 target_ulong sc_macl;
3098
3099 /* FPU registers */
3100 target_ulong sc_fpregs[16];
3101 target_ulong sc_xfpregs[16];
3102 unsigned int sc_fpscr;
3103 unsigned int sc_fpul;
3104 unsigned int sc_ownedfp;
3105};
3106
3107struct target_sigframe
3108{
3109 struct target_sigcontext sc;
3110 target_ulong extramask[TARGET_NSIG_WORDS-1];
3111 uint16_t retcode[3];
3112};
3113
3114
3115struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003116 target_ulong tuc_flags;
3117 struct target_ucontext *tuc_link;
3118 target_stack_t tuc_stack;
3119 struct target_sigcontext tuc_mcontext;
3120 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003121};
3122
3123struct target_rt_sigframe
3124{
3125 struct target_siginfo info;
3126 struct target_ucontext uc;
3127 uint16_t retcode[3];
3128};
3129
3130
3131#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3132#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3133
pbrook624f7972008-05-31 16:11:38 +00003134static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003135 unsigned long sp, size_t frame_size)
3136{
pbrook624f7972008-05-31 16:11:38 +00003137 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003138 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3139 }
3140
3141 return (sp - frame_size) & -8ul;
3142}
3143
Riku Voipio41ecc722014-04-23 11:01:00 +03003144static void setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003145 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003146{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003147 int i;
thsc3b5bc82007-12-02 06:31:25 +00003148
Riku Voipio1d8b5122014-04-23 10:26:05 +03003149#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003150 COPY(gregs[0]); COPY(gregs[1]);
3151 COPY(gregs[2]); COPY(gregs[3]);
3152 COPY(gregs[4]); COPY(gregs[5]);
3153 COPY(gregs[6]); COPY(gregs[7]);
3154 COPY(gregs[8]); COPY(gregs[9]);
3155 COPY(gregs[10]); COPY(gregs[11]);
3156 COPY(gregs[12]); COPY(gregs[13]);
3157 COPY(gregs[14]); COPY(gregs[15]);
3158 COPY(gbr); COPY(mach);
3159 COPY(macl); COPY(pr);
3160 COPY(sr); COPY(pc);
3161#undef COPY
3162
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003163 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003164 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003165 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003166 __put_user(regs->fpscr, &sc->sc_fpscr);
3167 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003168
3169 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003170 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003171}
3172
Riku Voipio016d2e12014-04-23 11:19:48 +03003173static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003174 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003175{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003176 int i;
thsc3b5bc82007-12-02 06:31:25 +00003177
Riku Voipio1d8b5122014-04-23 10:26:05 +03003178#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003179 COPY(gregs[1]);
3180 COPY(gregs[2]); COPY(gregs[3]);
3181 COPY(gregs[4]); COPY(gregs[5]);
3182 COPY(gregs[6]); COPY(gregs[7]);
3183 COPY(gregs[8]); COPY(gregs[9]);
3184 COPY(gregs[10]); COPY(gregs[11]);
3185 COPY(gregs[12]); COPY(gregs[13]);
3186 COPY(gregs[14]); COPY(gregs[15]);
3187 COPY(gbr); COPY(mach);
3188 COPY(macl); COPY(pr);
3189 COPY(sr); COPY(pc);
3190#undef COPY
3191
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003192 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003193 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003194 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003195 __get_user(regs->fpscr, &sc->sc_fpscr);
3196 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003197
3198 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003199 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003200}
3201
pbrook624f7972008-05-31 16:11:38 +00003202static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003203 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003204{
3205 struct target_sigframe *frame;
3206 abi_ulong frame_addr;
3207 int i;
thsc3b5bc82007-12-02 06:31:25 +00003208
3209 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003210 trace_user_setup_frame(regs, frame_addr);
thsc3b5bc82007-12-02 06:31:25 +00003211 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3212 goto give_sigsegv;
3213
Riku Voipio41ecc722014-04-23 11:01:00 +03003214 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003215
3216 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003217 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003218 }
3219
3220 /* Set up to return from userspace. If provided, use a stub
3221 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003222 if (ka->sa_flags & TARGET_SA_RESTORER) {
3223 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003224 } else {
3225 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003226 abi_ulong retcode_addr = frame_addr +
3227 offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003228 __put_user(MOVW(2), &frame->retcode[0]);
3229 __put_user(TRAP_NOARG, &frame->retcode[1]);
3230 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003231 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003232 }
3233
thsc3b5bc82007-12-02 06:31:25 +00003234 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003235 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003236 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003237 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003238 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003239 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003240
3241 unlock_user_struct(frame, frame_addr, 1);
3242 return;
3243
3244give_sigsegv:
3245 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003246 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003247}
3248
pbrook624f7972008-05-31 16:11:38 +00003249static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003250 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003251 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003252{
3253 struct target_rt_sigframe *frame;
3254 abi_ulong frame_addr;
3255 int i;
thsc3b5bc82007-12-02 06:31:25 +00003256
3257 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003258 trace_user_setup_rt_frame(regs, frame_addr);
thsc3b5bc82007-12-02 06:31:25 +00003259 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3260 goto give_sigsegv;
3261
Peter Maydellf6c7a052015-01-08 12:19:48 +00003262 tswap_siginfo(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003263
3264 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003265 __put_user(0, &frame->uc.tuc_flags);
3266 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3267 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3268 &frame->uc.tuc_stack.ss_sp);
3269 __put_user(sas_ss_flags(regs->gregs[15]),
3270 &frame->uc.tuc_stack.ss_flags);
3271 __put_user(target_sigaltstack_used.ss_size,
3272 &frame->uc.tuc_stack.ss_size);
3273 setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003274 regs, set->sig[0]);
3275 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003276 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003277 }
3278
3279 /* Set up to return from userspace. If provided, use a stub
3280 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003281 if (ka->sa_flags & TARGET_SA_RESTORER) {
3282 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003283 } else {
3284 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003285 abi_ulong retcode_addr = frame_addr +
3286 offsetof(struct target_rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003287 __put_user(MOVW(2), &frame->retcode[0]);
3288 __put_user(TRAP_NOARG, &frame->retcode[1]);
3289 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003290 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003291 }
3292
thsc3b5bc82007-12-02 06:31:25 +00003293 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003294 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003295 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003296 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3297 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003298 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003299
3300 unlock_user_struct(frame, frame_addr, 1);
3301 return;
3302
3303give_sigsegv:
3304 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003305 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003306}
3307
Andreas Färber05390242012-02-25 03:37:53 +01003308long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003309{
3310 struct target_sigframe *frame;
3311 abi_ulong frame_addr;
3312 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003313 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003314 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003315 int i;
3316 int err = 0;
3317
thsc3b5bc82007-12-02 06:31:25 +00003318 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003319 trace_user_do_sigreturn(regs, frame_addr);
thsc3b5bc82007-12-02 06:31:25 +00003320 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3321 goto badframe;
3322
Riku Voipio1d8b5122014-04-23 10:26:05 +03003323 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003324 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003325 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003326 }
3327
3328 if (err)
3329 goto badframe;
3330
3331 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003332 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003333
Riku Voipio016d2e12014-04-23 11:19:48 +03003334 restore_sigcontext(regs, &frame->sc, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003335
3336 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003337 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003338
3339badframe:
3340 unlock_user_struct(frame, frame_addr, 0);
3341 force_sig(TARGET_SIGSEGV);
3342 return 0;
3343}
3344
Andreas Färber05390242012-02-25 03:37:53 +01003345long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003346{
3347 struct target_rt_sigframe *frame;
3348 abi_ulong frame_addr;
3349 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003350 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003351
thsc3b5bc82007-12-02 06:31:25 +00003352 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003353 trace_user_do_rt_sigreturn(regs, frame_addr);
thsc3b5bc82007-12-02 06:31:25 +00003354 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3355 goto badframe;
3356
Aurelien Jarno60e99242010-03-29 02:12:51 +02003357 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003358 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003359
Riku Voipio016d2e12014-04-23 11:19:48 +03003360 restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003361
3362 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003363 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003364 0, get_sp_from_cpustate(regs)) == -EFAULT)
3365 goto badframe;
3366
3367 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003368 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003369
3370badframe:
3371 unlock_user_struct(frame, frame_addr, 0);
3372 force_sig(TARGET_SIGSEGV);
3373 return 0;
3374}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003375#elif defined(TARGET_MICROBLAZE)
3376
3377struct target_sigcontext {
3378 struct target_pt_regs regs; /* needs to be first */
3379 uint32_t oldmask;
3380};
3381
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003382struct target_stack_t {
3383 abi_ulong ss_sp;
3384 int ss_flags;
3385 unsigned int ss_size;
3386};
3387
3388struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003389 abi_ulong tuc_flags;
3390 abi_ulong tuc_link;
3391 struct target_stack_t tuc_stack;
3392 struct target_sigcontext tuc_mcontext;
3393 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003394};
3395
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003396/* Signal frames. */
3397struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003398 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003399 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3400 uint32_t tramp[2];
3401};
3402
3403struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003404 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003405 struct ucontext uc;
3406 uint32_t tramp[2];
3407};
3408
Andreas Färber05390242012-02-25 03:37:53 +01003409static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003410{
3411 __put_user(env->regs[0], &sc->regs.r0);
3412 __put_user(env->regs[1], &sc->regs.r1);
3413 __put_user(env->regs[2], &sc->regs.r2);
3414 __put_user(env->regs[3], &sc->regs.r3);
3415 __put_user(env->regs[4], &sc->regs.r4);
3416 __put_user(env->regs[5], &sc->regs.r5);
3417 __put_user(env->regs[6], &sc->regs.r6);
3418 __put_user(env->regs[7], &sc->regs.r7);
3419 __put_user(env->regs[8], &sc->regs.r8);
3420 __put_user(env->regs[9], &sc->regs.r9);
3421 __put_user(env->regs[10], &sc->regs.r10);
3422 __put_user(env->regs[11], &sc->regs.r11);
3423 __put_user(env->regs[12], &sc->regs.r12);
3424 __put_user(env->regs[13], &sc->regs.r13);
3425 __put_user(env->regs[14], &sc->regs.r14);
3426 __put_user(env->regs[15], &sc->regs.r15);
3427 __put_user(env->regs[16], &sc->regs.r16);
3428 __put_user(env->regs[17], &sc->regs.r17);
3429 __put_user(env->regs[18], &sc->regs.r18);
3430 __put_user(env->regs[19], &sc->regs.r19);
3431 __put_user(env->regs[20], &sc->regs.r20);
3432 __put_user(env->regs[21], &sc->regs.r21);
3433 __put_user(env->regs[22], &sc->regs.r22);
3434 __put_user(env->regs[23], &sc->regs.r23);
3435 __put_user(env->regs[24], &sc->regs.r24);
3436 __put_user(env->regs[25], &sc->regs.r25);
3437 __put_user(env->regs[26], &sc->regs.r26);
3438 __put_user(env->regs[27], &sc->regs.r27);
3439 __put_user(env->regs[28], &sc->regs.r28);
3440 __put_user(env->regs[29], &sc->regs.r29);
3441 __put_user(env->regs[30], &sc->regs.r30);
3442 __put_user(env->regs[31], &sc->regs.r31);
3443 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3444}
3445
Andreas Färber05390242012-02-25 03:37:53 +01003446static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003447{
3448 __get_user(env->regs[0], &sc->regs.r0);
3449 __get_user(env->regs[1], &sc->regs.r1);
3450 __get_user(env->regs[2], &sc->regs.r2);
3451 __get_user(env->regs[3], &sc->regs.r3);
3452 __get_user(env->regs[4], &sc->regs.r4);
3453 __get_user(env->regs[5], &sc->regs.r5);
3454 __get_user(env->regs[6], &sc->regs.r6);
3455 __get_user(env->regs[7], &sc->regs.r7);
3456 __get_user(env->regs[8], &sc->regs.r8);
3457 __get_user(env->regs[9], &sc->regs.r9);
3458 __get_user(env->regs[10], &sc->regs.r10);
3459 __get_user(env->regs[11], &sc->regs.r11);
3460 __get_user(env->regs[12], &sc->regs.r12);
3461 __get_user(env->regs[13], &sc->regs.r13);
3462 __get_user(env->regs[14], &sc->regs.r14);
3463 __get_user(env->regs[15], &sc->regs.r15);
3464 __get_user(env->regs[16], &sc->regs.r16);
3465 __get_user(env->regs[17], &sc->regs.r17);
3466 __get_user(env->regs[18], &sc->regs.r18);
3467 __get_user(env->regs[19], &sc->regs.r19);
3468 __get_user(env->regs[20], &sc->regs.r20);
3469 __get_user(env->regs[21], &sc->regs.r21);
3470 __get_user(env->regs[22], &sc->regs.r22);
3471 __get_user(env->regs[23], &sc->regs.r23);
3472 __get_user(env->regs[24], &sc->regs.r24);
3473 __get_user(env->regs[25], &sc->regs.r25);
3474 __get_user(env->regs[26], &sc->regs.r26);
3475 __get_user(env->regs[27], &sc->regs.r27);
3476 __get_user(env->regs[28], &sc->regs.r28);
3477 __get_user(env->regs[29], &sc->regs.r29);
3478 __get_user(env->regs[30], &sc->regs.r30);
3479 __get_user(env->regs[31], &sc->regs.r31);
3480 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3481}
3482
3483static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003484 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003485{
3486 abi_ulong sp = env->regs[1];
3487
Riku Voipiob545f632014-07-15 17:01:55 +03003488 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003489 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003490 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003491
3492 return ((sp - frame_size) & -8UL);
3493}
3494
3495static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003496 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003497{
3498 struct target_signal_frame *frame;
3499 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003500 int i;
3501
3502 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003503 trace_user_setup_frame(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003504 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3505 goto badframe;
3506
3507 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003508 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003509
3510 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003511 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003512 }
3513
Richard Hendersonf711df62010-11-22 14:57:52 -08003514 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003515
3516 /* Set up to return from userspace. If provided, use a stub
3517 already in userspace. */
3518 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3519 if (ka->sa_flags & TARGET_SA_RESTORER) {
3520 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3521 } else {
3522 uint32_t t;
3523 /* Note, these encodings are _big endian_! */
3524 /* addi r12, r0, __NR_sigreturn */
3525 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003526 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003527 /* brki r14, 0x8 */
3528 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003529 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003530
3531 /* Return from sighandler will jump to the tramp.
3532 Negative 8 offset because return is rtsd r15, 8 */
3533 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3534 }
3535
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003536 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003537 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003538 /* Signal handler args: */
3539 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003540 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003541 /* arg 1: sigcontext */
3542 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003543
3544 /* Offset of 4 to handle microblaze rtid r14, 0 */
3545 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3546
3547 unlock_user_struct(frame, frame_addr, 1);
3548 return;
3549 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003550 force_sig(TARGET_SIGSEGV);
3551}
3552
3553static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003554 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003555 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003556{
3557 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3558}
3559
Andreas Färber05390242012-02-25 03:37:53 +01003560long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003561{
3562 struct target_signal_frame *frame;
3563 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003564 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003565 sigset_t set;
3566 int i;
3567
3568 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003569 trace_user_do_sigreturn(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003570 /* Make sure the guest isn't playing games. */
3571 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3572 goto badframe;
3573
3574 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003575 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003576 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003577 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003578 }
3579 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003580 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003581
Richard Hendersonf711df62010-11-22 14:57:52 -08003582 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003583 /* We got here through a sigreturn syscall, our path back is via an
3584 rtb insn so setup r14 for that. */
3585 env->regs[14] = env->sregs[SR_PC];
3586
3587 unlock_user_struct(frame, frame_addr, 0);
3588 return env->regs[10];
3589 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003590 force_sig(TARGET_SIGSEGV);
3591}
3592
Andreas Färber05390242012-02-25 03:37:53 +01003593long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003594{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003595 trace_user_do_rt_sigreturn(env, 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003596 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3597 return -TARGET_ENOSYS;
3598}
3599
edgar_iglb6d3abd2008-02-28 11:29:27 +00003600#elif defined(TARGET_CRIS)
3601
3602struct target_sigcontext {
3603 struct target_pt_regs regs; /* needs to be first */
3604 uint32_t oldmask;
3605 uint32_t usp; /* usp before stacking this gunk on it */
3606};
3607
3608/* Signal frames. */
3609struct target_signal_frame {
3610 struct target_sigcontext sc;
3611 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003612 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003613};
3614
3615struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003616 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003617 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003618 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003619 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003620 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003621};
3622
Andreas Färber05390242012-02-25 03:37:53 +01003623static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003624{
edgar_igl9664d922008-03-03 22:23:53 +00003625 __put_user(env->regs[0], &sc->regs.r0);
3626 __put_user(env->regs[1], &sc->regs.r1);
3627 __put_user(env->regs[2], &sc->regs.r2);
3628 __put_user(env->regs[3], &sc->regs.r3);
3629 __put_user(env->regs[4], &sc->regs.r4);
3630 __put_user(env->regs[5], &sc->regs.r5);
3631 __put_user(env->regs[6], &sc->regs.r6);
3632 __put_user(env->regs[7], &sc->regs.r7);
3633 __put_user(env->regs[8], &sc->regs.r8);
3634 __put_user(env->regs[9], &sc->regs.r9);
3635 __put_user(env->regs[10], &sc->regs.r10);
3636 __put_user(env->regs[11], &sc->regs.r11);
3637 __put_user(env->regs[12], &sc->regs.r12);
3638 __put_user(env->regs[13], &sc->regs.r13);
3639 __put_user(env->regs[14], &sc->usp);
3640 __put_user(env->regs[15], &sc->regs.acr);
3641 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3642 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3643 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003644}
edgar_igl9664d922008-03-03 22:23:53 +00003645
Andreas Färber05390242012-02-25 03:37:53 +01003646static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003647{
edgar_igl9664d922008-03-03 22:23:53 +00003648 __get_user(env->regs[0], &sc->regs.r0);
3649 __get_user(env->regs[1], &sc->regs.r1);
3650 __get_user(env->regs[2], &sc->regs.r2);
3651 __get_user(env->regs[3], &sc->regs.r3);
3652 __get_user(env->regs[4], &sc->regs.r4);
3653 __get_user(env->regs[5], &sc->regs.r5);
3654 __get_user(env->regs[6], &sc->regs.r6);
3655 __get_user(env->regs[7], &sc->regs.r7);
3656 __get_user(env->regs[8], &sc->regs.r8);
3657 __get_user(env->regs[9], &sc->regs.r9);
3658 __get_user(env->regs[10], &sc->regs.r10);
3659 __get_user(env->regs[11], &sc->regs.r11);
3660 __get_user(env->regs[12], &sc->regs.r12);
3661 __get_user(env->regs[13], &sc->regs.r13);
3662 __get_user(env->regs[14], &sc->usp);
3663 __get_user(env->regs[15], &sc->regs.acr);
3664 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3665 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3666 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003667}
3668
Andreas Färber05390242012-02-25 03:37:53 +01003669static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003670{
edgar_igl9664d922008-03-03 22:23:53 +00003671 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003672 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003673 sp = (env->regs[R_SP] & ~3);
3674 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003675}
3676
pbrook624f7972008-05-31 16:11:38 +00003677static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003678 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003679{
3680 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003681 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003682 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003683
edgar_igl9664d922008-03-03 22:23:53 +00003684 frame_addr = get_sigframe(env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003685 trace_user_setup_frame(env, frame_addr);
edgar_igl9664d922008-03-03 22:23:53 +00003686 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003687 goto badframe;
3688
3689 /*
3690 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3691 * use this trampoline anymore but it sets it up for GDB.
3692 * In QEMU, using the trampoline simplifies things a bit so we use it.
3693 *
3694 * This is movu.w __NR_sigreturn, r9; break 13;
3695 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003696 __put_user(0x9c5f, frame->retcode+0);
3697 __put_user(TARGET_NR_sigreturn,
3698 frame->retcode + 1);
3699 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003700
3701 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003702 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003703
Riku Voipio0188fad2014-04-23 13:34:15 +03003704 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3705 __put_user(set->sig[i], &frame->extramask[i - 1]);
3706 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003707
3708 setup_sigcontext(&frame->sc, env);
3709
3710 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003711 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003712 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003713 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003714 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003715 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003716
edgar_igl9664d922008-03-03 22:23:53 +00003717 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003718 return;
3719 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003720 force_sig(TARGET_SIGSEGV);
3721}
3722
pbrook624f7972008-05-31 16:11:38 +00003723static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003724 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003725 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003726{
3727 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3728}
3729
Andreas Färber05390242012-02-25 03:37:53 +01003730long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003731{
3732 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003733 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003734 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003735 sigset_t set;
3736 int i;
3737
edgar_igl9664d922008-03-03 22:23:53 +00003738 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003739 trace_user_do_sigreturn(env, frame_addr);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003740 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003741 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003742 goto badframe;
3743
3744 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003745 __get_user(target_set.sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003746 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003747 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003748 }
3749 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003750 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003751
3752 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003753 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003754 return env->regs[10];
3755 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003756 force_sig(TARGET_SIGSEGV);
3757}
3758
Andreas Färber05390242012-02-25 03:37:53 +01003759long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003760{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003761 trace_user_do_rt_sigreturn(env, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003762 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3763 return -TARGET_ENOSYS;
3764}
thsc3b5bc82007-12-02 06:31:25 +00003765
Jia Liud9627832012-07-20 15:50:52 +08003766#elif defined(TARGET_OPENRISC)
3767
3768struct target_sigcontext {
3769 struct target_pt_regs regs;
3770 abi_ulong oldmask;
3771 abi_ulong usp;
3772};
3773
3774struct target_ucontext {
3775 abi_ulong tuc_flags;
3776 abi_ulong tuc_link;
3777 target_stack_t tuc_stack;
3778 struct target_sigcontext tuc_mcontext;
3779 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3780};
3781
3782struct target_rt_sigframe {
3783 abi_ulong pinfo;
3784 uint64_t puc;
3785 struct target_siginfo info;
3786 struct target_sigcontext sc;
3787 struct target_ucontext uc;
3788 unsigned char retcode[16]; /* trampoline code */
3789};
3790
3791/* This is the asm-generic/ucontext.h version */
3792#if 0
3793static int restore_sigcontext(CPUOpenRISCState *regs,
3794 struct target_sigcontext *sc)
3795{
3796 unsigned int err = 0;
3797 unsigned long old_usp;
3798
3799 /* Alwys make any pending restarted system call return -EINTR */
3800 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3801
3802 /* restore the regs from &sc->regs (same as sc, since regs is first)
3803 * (sc is already checked for VERIFY_READ since the sigframe was
3804 * checked in sys_sigreturn previously)
3805 */
3806
3807 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3808 goto badframe;
3809 }
3810
3811 /* make sure the U-flag is set so user-mode cannot fool us */
3812
3813 regs->sr &= ~SR_SM;
3814
3815 /* restore the old USP as it was before we stacked the sc etc.
3816 * (we cannot just pop the sigcontext since we aligned the sp and
3817 * stuff after pushing it)
3818 */
3819
Riku Voipio1d8b5122014-04-23 10:26:05 +03003820 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003821 phx_signal("old_usp 0x%lx", old_usp);
3822
3823 __PHX__ REALLY /* ??? */
3824 wrusp(old_usp);
3825 regs->gpr[1] = old_usp;
3826
3827 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3828 * after this completes, but we don't use that mechanism. maybe we can
3829 * use it now ?
3830 */
3831
3832 return err;
3833
3834badframe:
3835 return 1;
3836}
3837#endif
3838
3839/* Set up a signal frame. */
3840
Riku Voipio41ecc722014-04-23 11:01:00 +03003841static void setup_sigcontext(struct target_sigcontext *sc,
Jia Liud9627832012-07-20 15:50:52 +08003842 CPUOpenRISCState *regs,
3843 unsigned long mask)
3844{
Jia Liud9627832012-07-20 15:50:52 +08003845 unsigned long usp = regs->gpr[1];
3846
3847 /* copy the regs. they are first in sc so we can use sc directly */
3848
Riku Voipio1d8b5122014-04-23 10:26:05 +03003849 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003850
3851 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3852 the signal handler. The frametype will be restored to its previous
3853 value in restore_sigcontext. */
3854 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3855
3856 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003857 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003858 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003859}
3860
3861static inline unsigned long align_sigframe(unsigned long sp)
3862{
3863 unsigned long i;
3864 i = sp & ~3UL;
3865 return i;
3866}
3867
3868static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3869 CPUOpenRISCState *regs,
3870 size_t frame_size)
3871{
3872 unsigned long sp = regs->gpr[1];
3873 int onsigstack = on_sig_stack(sp);
3874
3875 /* redzone */
3876 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03003877 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08003878 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3879 }
3880
3881 sp = align_sigframe(sp - frame_size);
3882
3883 /*
3884 * If we are on the alternate signal stack and would overflow it, don't.
3885 * Return an always-bogus address instead so we will die with SIGSEGV.
3886 */
3887
3888 if (onsigstack && !likely(on_sig_stack(sp))) {
3889 return -1L;
3890 }
3891
3892 return sp;
3893}
3894
Jia Liud9627832012-07-20 15:50:52 +08003895static void setup_rt_frame(int sig, struct target_sigaction *ka,
3896 target_siginfo_t *info,
3897 target_sigset_t *set, CPUOpenRISCState *env)
3898{
3899 int err = 0;
3900 abi_ulong frame_addr;
3901 unsigned long return_ip;
3902 struct target_rt_sigframe *frame;
3903 abi_ulong info_addr, uc_addr;
3904
Jia Liud9627832012-07-20 15:50:52 +08003905 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003906 trace_user_setup_rt_frame(env, frame_addr);
Jia Liud9627832012-07-20 15:50:52 +08003907 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3908 goto give_sigsegv;
3909 }
3910
3911 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003912 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08003913 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003914 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08003915
3916 if (ka->sa_flags & SA_SIGINFO) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00003917 tswap_siginfo(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08003918 }
3919
3920 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03003921 __put_user(0, &frame->uc.tuc_flags);
3922 __put_user(0, &frame->uc.tuc_link);
3923 __put_user(target_sigaltstack_used.ss_sp,
3924 &frame->uc.tuc_stack.ss_sp);
3925 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3926 __put_user(target_sigaltstack_used.ss_size,
3927 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03003928 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08003929
3930 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3931
Jia Liud9627832012-07-20 15:50:52 +08003932 /* trampoline - the desired return ip is the retcode itself */
3933 return_ip = (unsigned long)&frame->retcode;
3934 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003935 __put_user(0xa960, (short *)(frame->retcode + 0));
3936 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
3937 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
3938 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08003939
3940 if (err) {
3941 goto give_sigsegv;
3942 }
3943
3944 /* TODO what is the current->exec_domain stuff and invmap ? */
3945
3946 /* Set up registers for signal handler */
3947 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
3948 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
3949 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
3950 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
3951 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
3952
3953 /* actually move the usp to reflect the stacked frame */
3954 env->gpr[1] = (unsigned long)frame;
3955
3956 return;
3957
3958give_sigsegv:
3959 unlock_user_struct(frame, frame_addr, 1);
3960 if (sig == TARGET_SIGSEGV) {
3961 ka->_sa_handler = TARGET_SIG_DFL;
3962 }
3963 force_sig(TARGET_SIGSEGV);
3964}
3965
3966long do_sigreturn(CPUOpenRISCState *env)
3967{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003968 trace_user_do_sigreturn(env, 0);
3969 fprintf(stderr, "do_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08003970 return -TARGET_ENOSYS;
3971}
3972
3973long do_rt_sigreturn(CPUOpenRISCState *env)
3974{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003975 trace_user_do_rt_sigreturn(env, 0);
3976 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08003977 return -TARGET_ENOSYS;
3978}
3979/* TARGET_OPENRISC */
3980
Ulrich Hechta4c075f2009-07-24 16:57:31 +02003981#elif defined(TARGET_S390X)
3982
3983#define __NUM_GPRS 16
3984#define __NUM_FPRS 16
3985#define __NUM_ACRS 16
3986
3987#define S390_SYSCALL_SIZE 2
3988#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
3989
3990#define _SIGCONTEXT_NSIG 64
3991#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
3992#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
3993#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
3994#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
3995#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
3996
3997typedef struct {
3998 target_psw_t psw;
3999 target_ulong gprs[__NUM_GPRS];
4000 unsigned int acrs[__NUM_ACRS];
4001} target_s390_regs_common;
4002
4003typedef struct {
4004 unsigned int fpc;
4005 double fprs[__NUM_FPRS];
4006} target_s390_fp_regs;
4007
4008typedef struct {
4009 target_s390_regs_common regs;
4010 target_s390_fp_regs fpregs;
4011} target_sigregs;
4012
4013struct target_sigcontext {
4014 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4015 target_sigregs *sregs;
4016};
4017
4018typedef struct {
4019 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4020 struct target_sigcontext sc;
4021 target_sigregs sregs;
4022 int signo;
4023 uint8_t retcode[S390_SYSCALL_SIZE];
4024} sigframe;
4025
4026struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004027 target_ulong tuc_flags;
4028 struct target_ucontext *tuc_link;
4029 target_stack_t tuc_stack;
4030 target_sigregs tuc_mcontext;
4031 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004032};
4033
4034typedef struct {
4035 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4036 uint8_t retcode[S390_SYSCALL_SIZE];
4037 struct target_siginfo info;
4038 struct target_ucontext uc;
4039} rt_sigframe;
4040
4041static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004042get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004043{
4044 abi_ulong sp;
4045
4046 /* Default to using normal stack */
4047 sp = env->regs[15];
4048
4049 /* This is the X/Open sanctioned signal stack switching. */
4050 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4051 if (!sas_ss_flags(sp)) {
4052 sp = target_sigaltstack_used.ss_sp +
4053 target_sigaltstack_used.ss_size;
4054 }
4055 }
4056
4057 /* This is the legacy signal stack switching. */
4058 else if (/* FIXME !user_mode(regs) */ 0 &&
4059 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4060 ka->sa_restorer) {
4061 sp = (abi_ulong) ka->sa_restorer;
4062 }
4063
4064 return (sp - frame_size) & -8ul;
4065}
4066
Andreas Färber05390242012-02-25 03:37:53 +01004067static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004068{
4069 int i;
4070 //save_access_regs(current->thread.acrs); FIXME
4071
4072 /* Copy a 'clean' PSW mask to the user to avoid leaking
4073 information about whether PER is currently on. */
4074 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4075 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4076 for (i = 0; i < 16; i++) {
4077 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4078 }
4079 for (i = 0; i < 16; i++) {
4080 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4081 }
4082 /*
4083 * We have to store the fp registers to current->thread.fp_regs
4084 * to merge them with the emulated registers.
4085 */
4086 //save_fp_regs(&current->thread.fp_regs); FIXME
4087 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004088 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004089 }
4090}
4091
4092static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004093 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004094{
4095 sigframe *frame;
4096 abi_ulong frame_addr;
4097
4098 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004099 trace_user_setup_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004100 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4101 goto give_sigsegv;
4102 }
4103
Riku Voipio0188fad2014-04-23 13:34:15 +03004104 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004105
4106 save_sigregs(env, &frame->sregs);
4107
4108 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4109 (abi_ulong *)&frame->sc.sregs);
4110
4111 /* Set up to return from userspace. If provided, use a stub
4112 already in userspace. */
4113 if (ka->sa_flags & TARGET_SA_RESTORER) {
4114 env->regs[14] = (unsigned long)
4115 ka->sa_restorer | PSW_ADDR_AMODE;
4116 } else {
4117 env->regs[14] = (unsigned long)
4118 frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004119 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4120 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004121 }
4122
4123 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004124 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004125
4126 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004127 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004128 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4129
4130 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004131 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004132
4133 /* We forgot to include these in the sigcontext.
4134 To avoid breaking binary compatibility, they are passed as args. */
4135 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4136 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4137
4138 /* Place signal number on stack to allow backtrace from handler. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004139 __put_user(env->regs[2], (int *) &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004140 unlock_user_struct(frame, frame_addr, 1);
4141 return;
4142
4143give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004144 force_sig(TARGET_SIGSEGV);
4145}
4146
4147static void setup_rt_frame(int sig, struct target_sigaction *ka,
4148 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004149 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004150{
4151 int i;
4152 rt_sigframe *frame;
4153 abi_ulong frame_addr;
4154
4155 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004156 trace_user_setup_rt_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004157 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4158 goto give_sigsegv;
4159 }
4160
Peter Maydellf6c7a052015-01-08 12:19:48 +00004161 tswap_siginfo(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004162
4163 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004164 __put_user(0, &frame->uc.tuc_flags);
4165 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4166 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004167 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004168 &frame->uc.tuc_stack.ss_flags);
4169 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4170 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004171 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4172 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004173 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004174 }
4175
4176 /* Set up to return from userspace. If provided, use a stub
4177 already in userspace. */
4178 if (ka->sa_flags & TARGET_SA_RESTORER) {
4179 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4180 } else {
4181 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004182 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4183 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004184 }
4185
4186 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004187 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004188
4189 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004190 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004191 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4192
4193 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004194 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4195 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004196 return;
4197
4198give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004199 force_sig(TARGET_SIGSEGV);
4200}
4201
4202static int
Andreas Färber05390242012-02-25 03:37:53 +01004203restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004204{
4205 int err = 0;
4206 int i;
4207
4208 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004209 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004210 }
4211
Riku Voipio1d8b5122014-04-23 10:26:05 +03004212 __get_user(env->psw.mask, &sc->regs.psw.mask);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004213 trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
4214 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004215 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004216 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4217
4218 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004219 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004220 }
4221 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004222 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004223 }
4224
4225 return err;
4226}
4227
Andreas Färber05390242012-02-25 03:37:53 +01004228long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004229{
4230 sigframe *frame;
4231 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004232 target_sigset_t target_set;
4233 sigset_t set;
4234
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004235 trace_user_do_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004236 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4237 goto badframe;
4238 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004239 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004240
4241 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004242 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004243
4244 if (restore_sigregs(env, &frame->sregs)) {
4245 goto badframe;
4246 }
4247
4248 unlock_user_struct(frame, frame_addr, 0);
4249 return env->regs[2];
4250
4251badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004252 force_sig(TARGET_SIGSEGV);
4253 return 0;
4254}
4255
Andreas Färber05390242012-02-25 03:37:53 +01004256long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004257{
4258 rt_sigframe *frame;
4259 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004260 sigset_t set;
4261
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004262 trace_user_do_rt_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004263 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4264 goto badframe;
4265 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004266 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004267
Alex Barcelo1c275922014-03-14 14:36:55 +00004268 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004269
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004270 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004271 goto badframe;
4272 }
4273
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004274 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004275 get_sp_from_cpustate(env)) == -EFAULT) {
4276 goto badframe;
4277 }
4278 unlock_user_struct(frame, frame_addr, 0);
4279 return env->regs[2];
4280
4281badframe:
4282 unlock_user_struct(frame, frame_addr, 0);
4283 force_sig(TARGET_SIGSEGV);
4284 return 0;
4285}
4286
Tom Musta61e75fe2014-06-30 08:13:38 -05004287#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004288
4289/* Size of dummy stack frame allocated when calling signal handler.
4290 See arch/powerpc/include/asm/ptrace.h. */
4291#if defined(TARGET_PPC64)
4292#define SIGNAL_FRAMESIZE 128
4293#else
4294#define SIGNAL_FRAMESIZE 64
4295#endif
4296
Tom Musta61e75fe2014-06-30 08:13:38 -05004297/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4298 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4299struct target_mcontext {
4300 target_ulong mc_gregs[48];
4301 /* Includes fpscr. */
4302 uint64_t mc_fregs[33];
4303 target_ulong mc_pad[2];
4304 /* We need to handle Altivec and SPE at the same time, which no
4305 kernel needs to do. Fortunately, the kernel defines this bit to
4306 be Altivec-register-large all the time, rather than trying to
4307 twiddle it based on the specific platform. */
4308 union {
4309 /* SPE vector registers. One extra for SPEFSCR. */
4310 uint32_t spe[33];
4311 /* Altivec vector registers. The packing of VSCR and VRSAVE
4312 varies depending on whether we're PPC64 or not: PPC64 splits
4313 them apart; PPC32 stuffs them together. */
4314#if defined(TARGET_PPC64)
4315#define QEMU_NVRREG 34
4316#else
4317#define QEMU_NVRREG 33
4318#endif
4319 ppc_avr_t altivec[QEMU_NVRREG];
4320#undef QEMU_NVRREG
4321 } mc_vregs __attribute__((__aligned__(16)));
4322};
4323
Nathan Froydbcd49332009-05-12 19:13:18 -07004324/* See arch/powerpc/include/asm/sigcontext.h. */
4325struct target_sigcontext {
4326 target_ulong _unused[4];
4327 int32_t signal;
4328#if defined(TARGET_PPC64)
4329 int32_t pad0;
4330#endif
4331 target_ulong handler;
4332 target_ulong oldmask;
4333 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004334#if defined(TARGET_PPC64)
4335 struct target_mcontext mcontext;
4336#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004337};
4338
4339/* Indices for target_mcontext.mc_gregs, below.
4340 See arch/powerpc/include/asm/ptrace.h for details. */
4341enum {
4342 TARGET_PT_R0 = 0,
4343 TARGET_PT_R1 = 1,
4344 TARGET_PT_R2 = 2,
4345 TARGET_PT_R3 = 3,
4346 TARGET_PT_R4 = 4,
4347 TARGET_PT_R5 = 5,
4348 TARGET_PT_R6 = 6,
4349 TARGET_PT_R7 = 7,
4350 TARGET_PT_R8 = 8,
4351 TARGET_PT_R9 = 9,
4352 TARGET_PT_R10 = 10,
4353 TARGET_PT_R11 = 11,
4354 TARGET_PT_R12 = 12,
4355 TARGET_PT_R13 = 13,
4356 TARGET_PT_R14 = 14,
4357 TARGET_PT_R15 = 15,
4358 TARGET_PT_R16 = 16,
4359 TARGET_PT_R17 = 17,
4360 TARGET_PT_R18 = 18,
4361 TARGET_PT_R19 = 19,
4362 TARGET_PT_R20 = 20,
4363 TARGET_PT_R21 = 21,
4364 TARGET_PT_R22 = 22,
4365 TARGET_PT_R23 = 23,
4366 TARGET_PT_R24 = 24,
4367 TARGET_PT_R25 = 25,
4368 TARGET_PT_R26 = 26,
4369 TARGET_PT_R27 = 27,
4370 TARGET_PT_R28 = 28,
4371 TARGET_PT_R29 = 29,
4372 TARGET_PT_R30 = 30,
4373 TARGET_PT_R31 = 31,
4374 TARGET_PT_NIP = 32,
4375 TARGET_PT_MSR = 33,
4376 TARGET_PT_ORIG_R3 = 34,
4377 TARGET_PT_CTR = 35,
4378 TARGET_PT_LNK = 36,
4379 TARGET_PT_XER = 37,
4380 TARGET_PT_CCR = 38,
4381 /* Yes, there are two registers with #39. One is 64-bit only. */
4382 TARGET_PT_MQ = 39,
4383 TARGET_PT_SOFTE = 39,
4384 TARGET_PT_TRAP = 40,
4385 TARGET_PT_DAR = 41,
4386 TARGET_PT_DSISR = 42,
4387 TARGET_PT_RESULT = 43,
4388 TARGET_PT_REGS_COUNT = 44
4389};
4390
Nathan Froydbcd49332009-05-12 19:13:18 -07004391
4392struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004393 target_ulong tuc_flags;
4394 target_ulong tuc_link; /* struct ucontext __user * */
4395 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004396#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004397 int32_t tuc_pad[7];
4398 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004399 points to uc_mcontext field */
4400#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004401 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004402#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004403 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004404 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004405#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004406 int32_t tuc_maskext[30];
4407 int32_t tuc_pad2[3];
4408 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004409#endif
4410};
4411
4412/* See arch/powerpc/kernel/signal_32.c. */
4413struct target_sigframe {
4414 struct target_sigcontext sctx;
4415 struct target_mcontext mctx;
4416 int32_t abigap[56];
4417};
4418
Tom Musta61e75fe2014-06-30 08:13:38 -05004419#if defined(TARGET_PPC64)
4420
4421#define TARGET_TRAMP_SIZE 6
4422
4423struct target_rt_sigframe {
4424 /* sys_rt_sigreturn requires the ucontext be the first field */
4425 struct target_ucontext uc;
4426 target_ulong _unused[2];
4427 uint32_t trampoline[TARGET_TRAMP_SIZE];
4428 target_ulong pinfo; /* struct siginfo __user * */
4429 target_ulong puc; /* void __user * */
4430 struct target_siginfo info;
4431 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4432 char abigap[288];
4433} __attribute__((aligned(16)));
4434
4435#else
4436
Nathan Froydbcd49332009-05-12 19:13:18 -07004437struct target_rt_sigframe {
4438 struct target_siginfo info;
4439 struct target_ucontext uc;
4440 int32_t abigap[56];
4441};
4442
Tom Musta61e75fe2014-06-30 08:13:38 -05004443#endif
4444
Tom Musta8d6ab332014-06-30 08:13:39 -05004445#if defined(TARGET_PPC64)
4446
4447struct target_func_ptr {
4448 target_ulong entry;
4449 target_ulong toc;
4450};
4451
4452#endif
4453
Nathan Froydbcd49332009-05-12 19:13:18 -07004454/* We use the mc_pad field for the signal return trampoline. */
4455#define tramp mc_pad
4456
4457/* See arch/powerpc/kernel/signal.c. */
4458static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004459 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004460 int frame_size)
4461{
4462 target_ulong oldsp, newsp;
4463
4464 oldsp = env->gpr[1];
4465
4466 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004467 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004468 oldsp = (target_sigaltstack_used.ss_sp
4469 + target_sigaltstack_used.ss_size);
4470 }
4471
4472 newsp = (oldsp - frame_size) & ~0xFUL;
4473
4474 return newsp;
4475}
4476
Tom Musta76781082014-06-30 08:13:37 -05004477static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004478{
4479 target_ulong msr = env->msr;
4480 int i;
4481 target_ulong ccr = 0;
4482
4483 /* In general, the kernel attempts to be intelligent about what it
4484 needs to save for Altivec/FP/SPE registers. We don't care that
4485 much, so we just go ahead and save everything. */
4486
4487 /* Save general registers. */
4488 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004489 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004490 }
Riku Voipioc650c002014-04-23 13:53:45 +03004491 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4492 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4493 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4494 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004495
4496 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4497 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4498 }
Riku Voipioc650c002014-04-23 13:53:45 +03004499 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004500
4501 /* Save Altivec registers if necessary. */
4502 if (env->insns_flags & PPC_ALTIVEC) {
4503 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004504 ppc_avr_t *avr = &env->avr[i];
4505 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004506
Riku Voipioc650c002014-04-23 13:53:45 +03004507 __put_user(avr->u64[0], &vreg->u64[0]);
4508 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004509 }
4510 /* Set MSR_VR in the saved MSR value to indicate that
4511 frame->mc_vregs contains valid data. */
4512 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004513 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4514 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004515 }
4516
4517 /* Save floating point registers. */
4518 if (env->insns_flags & PPC_FLOAT) {
4519 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004520 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004521 }
Riku Voipioc650c002014-04-23 13:53:45 +03004522 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004523 }
4524
4525 /* Save SPE registers. The kernel only saves the high half. */
4526 if (env->insns_flags & PPC_SPE) {
4527#if defined(TARGET_PPC64)
4528 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004529 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004530 }
4531#else
4532 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004533 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004534 }
4535#endif
4536 /* Set MSR_SPE in the saved MSR value to indicate that
4537 frame->mc_vregs contains valid data. */
4538 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004539 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004540 }
4541
4542 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004543 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004544}
Nathan Froydbcd49332009-05-12 19:13:18 -07004545
Tom Musta76781082014-06-30 08:13:37 -05004546static void encode_trampoline(int sigret, uint32_t *tramp)
4547{
Nathan Froydbcd49332009-05-12 19:13:18 -07004548 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4549 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004550 __put_user(0x38000000 | sigret, &tramp[0]);
4551 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004552 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004553}
4554
Riku Voipioc650c002014-04-23 13:53:45 +03004555static void restore_user_regs(CPUPPCState *env,
4556 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004557{
4558 target_ulong save_r2 = 0;
4559 target_ulong msr;
4560 target_ulong ccr;
4561
4562 int i;
4563
4564 if (!sig) {
4565 save_r2 = env->gpr[2];
4566 }
4567
4568 /* Restore general registers. */
4569 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004570 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004571 }
Riku Voipioc650c002014-04-23 13:53:45 +03004572 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4573 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4574 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4575 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4576 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004577
4578 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4579 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4580 }
4581
4582 if (!sig) {
4583 env->gpr[2] = save_r2;
4584 }
4585 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004586 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004587
4588 /* If doing signal return, restore the previous little-endian mode. */
4589 if (sig)
4590 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4591
4592 /* Restore Altivec registers if necessary. */
4593 if (env->insns_flags & PPC_ALTIVEC) {
4594 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004595 ppc_avr_t *avr = &env->avr[i];
4596 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004597
Riku Voipioc650c002014-04-23 13:53:45 +03004598 __get_user(avr->u64[0], &vreg->u64[0]);
4599 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004600 }
4601 /* Set MSR_VEC in the saved MSR value to indicate that
4602 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004603 __get_user(env->spr[SPR_VRSAVE],
4604 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004605 }
4606
4607 /* Restore floating point registers. */
4608 if (env->insns_flags & PPC_FLOAT) {
4609 uint64_t fpscr;
4610 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004611 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004612 }
Riku Voipioc650c002014-04-23 13:53:45 +03004613 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004614 env->fpscr = (uint32_t) fpscr;
4615 }
4616
4617 /* Save SPE registers. The kernel only saves the high half. */
4618 if (env->insns_flags & PPC_SPE) {
4619#if defined(TARGET_PPC64)
4620 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4621 uint32_t hi;
4622
Riku Voipioc650c002014-04-23 13:53:45 +03004623 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004624 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4625 }
4626#else
4627 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004628 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004629 }
4630#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004631 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004632 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004633}
4634
4635static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004636 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004637{
4638 struct target_sigframe *frame;
4639 struct target_sigcontext *sc;
4640 target_ulong frame_addr, newsp;
4641 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004642#if defined(TARGET_PPC64)
4643 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4644#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004645
4646 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004647 trace_user_setup_frame(env, frame_addr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004648 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4649 goto sigsegv;
4650 sc = &frame->sctx;
4651
Riku Voipio1d8b5122014-04-23 10:26:05 +03004652 __put_user(ka->_sa_handler, &sc->handler);
4653 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004654#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004655 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004656#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004657 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004658#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004659 __put_user(h2g(&frame->mctx), &sc->regs);
4660 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004661
4662 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004663 save_user_regs(env, &frame->mctx);
4664
4665 /* Construct the trampoline code on the stack. */
4666 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004667
4668 /* The kernel checks for the presence of a VDSO here. We don't
4669 emulate a vdso, so use a sigreturn system call. */
4670 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4671
4672 /* Turn off all fp exceptions. */
4673 env->fpscr = 0;
4674
4675 /* Create a stack frame for the caller of the handler. */
4676 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004677 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004678
4679 if (err)
4680 goto sigsegv;
4681
4682 /* Set up registers for signal handler. */
4683 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004684 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004685 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004686
4687#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004688 if (get_ppc64_abi(image) < 2) {
4689 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4690 struct target_func_ptr *handler =
4691 (struct target_func_ptr *)g2h(ka->_sa_handler);
4692 env->nip = tswapl(handler->entry);
4693 env->gpr[2] = tswapl(handler->toc);
4694 } else {
4695 /* ELFv2 PPC64 function pointers are entry points, but R12
4696 * must also be set */
4697 env->nip = tswapl((target_ulong) ka->_sa_handler);
4698 env->gpr[12] = env->nip;
4699 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004700#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004701 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004702#endif
4703
Nathan Froydbcd49332009-05-12 19:13:18 -07004704 /* Signal handlers are entered in big-endian mode. */
4705 env->msr &= ~MSR_LE;
4706
4707 unlock_user_struct(frame, frame_addr, 1);
4708 return;
4709
4710sigsegv:
4711 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004712 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004713}
4714
4715static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004716 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004717 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004718{
4719 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004720 uint32_t *trampptr = 0;
4721 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004722 target_ulong rt_sf_addr, newsp = 0;
4723 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004724#if defined(TARGET_PPC64)
4725 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4726#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004727
4728 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4729 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4730 goto sigsegv;
4731
Peter Maydellf6c7a052015-01-08 12:19:48 +00004732 tswap_siginfo(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004733
Riku Voipio1d8b5122014-04-23 10:26:05 +03004734 __put_user(0, &rt_sf->uc.tuc_flags);
4735 __put_user(0, &rt_sf->uc.tuc_link);
4736 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4737 &rt_sf->uc.tuc_stack.ss_sp);
4738 __put_user(sas_ss_flags(env->gpr[1]),
4739 &rt_sf->uc.tuc_stack.ss_flags);
4740 __put_user(target_sigaltstack_used.ss_size,
4741 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004742#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004743 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4744 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004745#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004746 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004747 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004748 }
4749
Tom Musta61e75fe2014-06-30 08:13:38 -05004750#if defined(TARGET_PPC64)
4751 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4752 trampptr = &rt_sf->trampoline[0];
4753#else
4754 mctx = &rt_sf->uc.tuc_mcontext;
4755 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4756#endif
4757
4758 save_user_regs(env, mctx);
4759 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004760
4761 /* The kernel checks for the presence of a VDSO here. We don't
4762 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004763 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004764
4765 /* Turn off all fp exceptions. */
4766 env->fpscr = 0;
4767
4768 /* Create a stack frame for the caller of the handler. */
4769 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004770 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004771
4772 if (err)
4773 goto sigsegv;
4774
4775 /* Set up registers for signal handler. */
4776 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004777 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004778 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4779 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4780 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004781
4782#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004783 if (get_ppc64_abi(image) < 2) {
4784 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4785 struct target_func_ptr *handler =
4786 (struct target_func_ptr *)g2h(ka->_sa_handler);
4787 env->nip = tswapl(handler->entry);
4788 env->gpr[2] = tswapl(handler->toc);
4789 } else {
4790 /* ELFv2 PPC64 function pointers are entry points, but R12
4791 * must also be set */
4792 env->nip = tswapl((target_ulong) ka->_sa_handler);
4793 env->gpr[12] = env->nip;
4794 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004795#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004796 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004797#endif
4798
Nathan Froydbcd49332009-05-12 19:13:18 -07004799 /* Signal handlers are entered in big-endian mode. */
4800 env->msr &= ~MSR_LE;
4801
4802 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4803 return;
4804
4805sigsegv:
4806 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004807 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004808
4809}
4810
Andreas Färber05390242012-02-25 03:37:53 +01004811long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004812{
4813 struct target_sigcontext *sc = NULL;
4814 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004815 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004816 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004817 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004818
4819 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4820 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4821 goto sigsegv;
4822
4823#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004824 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004825#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004826 __get_user(set.sig[0], &sc->oldmask);
4827 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004828#endif
4829 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004830 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004831
Riku Voipiof5f601a2014-04-23 13:00:17 +03004832 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004833 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4834 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004835 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004836
4837 unlock_user_struct(sr, sr_addr, 1);
4838 unlock_user_struct(sc, sc_addr, 1);
4839 return -TARGET_QEMU_ESIGRETURN;
4840
4841sigsegv:
4842 unlock_user_struct(sr, sr_addr, 1);
4843 unlock_user_struct(sc, sc_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004844 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004845 return 0;
4846}
4847
4848/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004849static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004850{
4851 struct target_mcontext *mcp;
4852 target_ulong mcp_addr;
4853 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004854 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004855
Aurelien Jarno60e99242010-03-29 02:12:51 +02004856 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004857 sizeof (set)))
4858 return 1;
4859
Tom Musta19774ec2014-06-30 08:13:40 -05004860#if defined(TARGET_PPC64)
4861 mcp_addr = h2g(ucp) +
4862 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4863#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004864 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004865#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004866
4867 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4868 return 1;
4869
4870 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004871 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Riku Voipioc650c002014-04-23 13:53:45 +03004872 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004873
4874 unlock_user_struct(mcp, mcp_addr, 1);
4875 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004876}
4877
Andreas Färber05390242012-02-25 03:37:53 +01004878long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004879{
4880 struct target_rt_sigframe *rt_sf = NULL;
4881 target_ulong rt_sf_addr;
4882
4883 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4884 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4885 goto sigsegv;
4886
4887 if (do_setcontext(&rt_sf->uc, env, 1))
4888 goto sigsegv;
4889
4890 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004891 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004892 0, env->gpr[1]);
4893
4894 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4895 return -TARGET_QEMU_ESIGRETURN;
4896
4897sigsegv:
4898 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004899 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004900 return 0;
4901}
4902
Laurent Vivier492a8742009-08-03 16:12:17 +02004903#elif defined(TARGET_M68K)
4904
4905struct target_sigcontext {
4906 abi_ulong sc_mask;
4907 abi_ulong sc_usp;
4908 abi_ulong sc_d0;
4909 abi_ulong sc_d1;
4910 abi_ulong sc_a0;
4911 abi_ulong sc_a1;
4912 unsigned short sc_sr;
4913 abi_ulong sc_pc;
4914};
4915
4916struct target_sigframe
4917{
4918 abi_ulong pretcode;
4919 int sig;
4920 int code;
4921 abi_ulong psc;
4922 char retcode[8];
4923 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4924 struct target_sigcontext sc;
4925};
Laurent Vivier71811552009-08-03 16:12:18 +02004926
Anthony Liguoric227f092009-10-01 16:12:16 -05004927typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004928#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004929typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004930
4931typedef struct target_fpregset {
4932 int f_fpcntl[3];
4933 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05004934} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004935
4936struct target_mcontext {
4937 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05004938 target_gregset_t gregs;
4939 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004940};
4941
4942#define TARGET_MCONTEXT_VERSION 2
4943
4944struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004945 abi_ulong tuc_flags;
4946 abi_ulong tuc_link;
4947 target_stack_t tuc_stack;
4948 struct target_mcontext tuc_mcontext;
4949 abi_long tuc_filler[80];
4950 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02004951};
4952
4953struct target_rt_sigframe
4954{
4955 abi_ulong pretcode;
4956 int sig;
4957 abi_ulong pinfo;
4958 abi_ulong puc;
4959 char retcode[8];
4960 struct target_siginfo info;
4961 struct target_ucontext uc;
4962};
Laurent Vivier492a8742009-08-03 16:12:17 +02004963
Riku Voipio41ecc722014-04-23 11:01:00 +03004964static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
4965 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02004966{
Riku Voipio1d8b5122014-04-23 10:26:05 +03004967 __put_user(mask, &sc->sc_mask);
4968 __put_user(env->aregs[7], &sc->sc_usp);
4969 __put_user(env->dregs[0], &sc->sc_d0);
4970 __put_user(env->dregs[1], &sc->sc_d1);
4971 __put_user(env->aregs[0], &sc->sc_a0);
4972 __put_user(env->aregs[1], &sc->sc_a1);
4973 __put_user(env->sr, &sc->sc_sr);
4974 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02004975}
4976
Riku Voipio016d2e12014-04-23 11:19:48 +03004977static void
Andreas Färber05390242012-02-25 03:37:53 +01004978restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02004979{
Laurent Vivier492a8742009-08-03 16:12:17 +02004980 int temp;
4981
Riku Voipio1d8b5122014-04-23 10:26:05 +03004982 __get_user(env->aregs[7], &sc->sc_usp);
4983 __get_user(env->dregs[1], &sc->sc_d1);
4984 __get_user(env->aregs[0], &sc->sc_a0);
4985 __get_user(env->aregs[1], &sc->sc_a1);
4986 __get_user(env->pc, &sc->sc_pc);
4987 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02004988 env->sr = (env->sr & 0xff00) | (temp & 0xff);
4989
4990 *pd0 = tswapl(sc->sc_d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02004991}
4992
4993/*
4994 * Determine which stack to use..
4995 */
4996static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004997get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
4998 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02004999{
5000 unsigned long sp;
5001
5002 sp = regs->aregs[7];
5003
5004 /* This is the X/Open sanctioned signal stack switching. */
5005 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5006 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5007 }
5008
5009 return ((sp - frame_size) & -8UL);
5010}
5011
5012static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005013 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005014{
5015 struct target_sigframe *frame;
5016 abi_ulong frame_addr;
5017 abi_ulong retcode_addr;
5018 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005019 int i;
5020
5021 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005022 trace_user_setup_frame(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005023 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5024 goto give_sigsegv;
5025
Riku Voipio1d8b5122014-04-23 10:26:05 +03005026 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005027
5028 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005029 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005030
Riku Voipio41ecc722014-04-23 11:01:00 +03005031 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005032
5033 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005034 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005035 }
5036
5037 /* Set up to return from userspace. */
5038
5039 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005040 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005041
5042 /* moveq #,d0; trap #0 */
5043
Riku Voipio1d8b5122014-04-23 10:26:05 +03005044 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005045 (uint32_t *)(frame->retcode));
Laurent Vivier492a8742009-08-03 16:12:17 +02005046
Laurent Vivier492a8742009-08-03 16:12:17 +02005047 /* Set up to return from userspace */
5048
5049 env->aregs[7] = frame_addr;
5050 env->pc = ka->_sa_handler;
5051
5052 unlock_user_struct(frame, frame_addr, 1);
5053 return;
5054
5055give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005056 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005057}
5058
Laurent Vivier71811552009-08-03 16:12:18 +02005059static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005060 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005061{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005062 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005063
Riku Voipio1d8b5122014-04-23 10:26:05 +03005064 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5065 __put_user(env->dregs[0], &gregs[0]);
5066 __put_user(env->dregs[1], &gregs[1]);
5067 __put_user(env->dregs[2], &gregs[2]);
5068 __put_user(env->dregs[3], &gregs[3]);
5069 __put_user(env->dregs[4], &gregs[4]);
5070 __put_user(env->dregs[5], &gregs[5]);
5071 __put_user(env->dregs[6], &gregs[6]);
5072 __put_user(env->dregs[7], &gregs[7]);
5073 __put_user(env->aregs[0], &gregs[8]);
5074 __put_user(env->aregs[1], &gregs[9]);
5075 __put_user(env->aregs[2], &gregs[10]);
5076 __put_user(env->aregs[3], &gregs[11]);
5077 __put_user(env->aregs[4], &gregs[12]);
5078 __put_user(env->aregs[5], &gregs[13]);
5079 __put_user(env->aregs[6], &gregs[14]);
5080 __put_user(env->aregs[7], &gregs[15]);
5081 __put_user(env->pc, &gregs[16]);
5082 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005083
Riku Voipio1d8b5122014-04-23 10:26:05 +03005084 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005085}
5086
Andreas Färber05390242012-02-25 03:37:53 +01005087static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005088 struct target_ucontext *uc,
5089 int *pd0)
5090{
5091 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005092 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005093
Riku Voipio1d8b5122014-04-23 10:26:05 +03005094 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005095 if (temp != TARGET_MCONTEXT_VERSION)
5096 goto badframe;
5097
5098 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005099 __get_user(env->dregs[0], &gregs[0]);
5100 __get_user(env->dregs[1], &gregs[1]);
5101 __get_user(env->dregs[2], &gregs[2]);
5102 __get_user(env->dregs[3], &gregs[3]);
5103 __get_user(env->dregs[4], &gregs[4]);
5104 __get_user(env->dregs[5], &gregs[5]);
5105 __get_user(env->dregs[6], &gregs[6]);
5106 __get_user(env->dregs[7], &gregs[7]);
5107 __get_user(env->aregs[0], &gregs[8]);
5108 __get_user(env->aregs[1], &gregs[9]);
5109 __get_user(env->aregs[2], &gregs[10]);
5110 __get_user(env->aregs[3], &gregs[11]);
5111 __get_user(env->aregs[4], &gregs[12]);
5112 __get_user(env->aregs[5], &gregs[13]);
5113 __get_user(env->aregs[6], &gregs[14]);
5114 __get_user(env->aregs[7], &gregs[15]);
5115 __get_user(env->pc, &gregs[16]);
5116 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005117 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5118
5119 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005120 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005121
5122badframe:
5123 return 1;
5124}
5125
Laurent Vivier492a8742009-08-03 16:12:17 +02005126static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005127 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005128 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005129{
Laurent Vivier71811552009-08-03 16:12:18 +02005130 struct target_rt_sigframe *frame;
5131 abi_ulong frame_addr;
5132 abi_ulong retcode_addr;
5133 abi_ulong info_addr;
5134 abi_ulong uc_addr;
5135 int err = 0;
5136 int i;
5137
5138 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005139 trace_user_setup_rt_frame(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005140 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5141 goto give_sigsegv;
5142
Riku Voipio1d8b5122014-04-23 10:26:05 +03005143 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005144
5145 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005146 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005147
5148 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005149 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005150
Peter Maydellf6c7a052015-01-08 12:19:48 +00005151 tswap_siginfo(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005152
5153 /* Create the ucontext */
5154
Riku Voipio1d8b5122014-04-23 10:26:05 +03005155 __put_user(0, &frame->uc.tuc_flags);
5156 __put_user(0, &frame->uc.tuc_link);
5157 __put_user(target_sigaltstack_used.ss_sp,
5158 &frame->uc.tuc_stack.ss_sp);
5159 __put_user(sas_ss_flags(env->aregs[7]),
5160 &frame->uc.tuc_stack.ss_flags);
5161 __put_user(target_sigaltstack_used.ss_size,
5162 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005163 err |= target_rt_setup_ucontext(&frame->uc, env);
5164
5165 if (err)
5166 goto give_sigsegv;
5167
5168 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005169 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005170 }
5171
5172 /* Set up to return from userspace. */
5173
5174 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005175 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005176
5177 /* moveq #,d0; notb d0; trap #0 */
5178
Riku Voipio1d8b5122014-04-23 10:26:05 +03005179 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005180 (uint32_t *)(frame->retcode + 0));
5181 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005182
5183 if (err)
5184 goto give_sigsegv;
5185
5186 /* Set up to return from userspace */
5187
5188 env->aregs[7] = frame_addr;
5189 env->pc = ka->_sa_handler;
5190
5191 unlock_user_struct(frame, frame_addr, 1);
5192 return;
5193
5194give_sigsegv:
5195 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005196 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005197}
5198
Andreas Färber05390242012-02-25 03:37:53 +01005199long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005200{
5201 struct target_sigframe *frame;
5202 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005203 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005204 sigset_t set;
5205 int d0, i;
5206
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005207 trace_user_do_sigreturn(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005208 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5209 goto badframe;
5210
5211 /* set blocked signals */
5212
Riku Voipiof5f601a2014-04-23 13:00:17 +03005213 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005214
5215 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005216 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005217 }
5218
5219 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005220 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005221
5222 /* restore registers */
5223
Riku Voipio016d2e12014-04-23 11:19:48 +03005224 restore_sigcontext(env, &frame->sc, &d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005225
5226 unlock_user_struct(frame, frame_addr, 0);
5227 return d0;
5228
5229badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005230 force_sig(TARGET_SIGSEGV);
5231 return 0;
5232}
5233
Andreas Färber05390242012-02-25 03:37:53 +01005234long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005235{
Laurent Vivier71811552009-08-03 16:12:18 +02005236 struct target_rt_sigframe *frame;
5237 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005238 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005239 sigset_t set;
5240 int d0;
5241
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005242 trace_user_do_rt_sigreturn(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005243 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5244 goto badframe;
5245
5246 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005247 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005248
5249 /* restore registers */
5250
5251 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5252 goto badframe;
5253
5254 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005255 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005256 0, get_sp_from_cpustate(env)) == -EFAULT)
5257 goto badframe;
5258
5259 unlock_user_struct(frame, frame_addr, 0);
5260 return d0;
5261
5262badframe:
5263 unlock_user_struct(frame, frame_addr, 0);
5264 force_sig(TARGET_SIGSEGV);
5265 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005266}
5267
Richard Henderson6049f4f2009-12-27 18:30:03 -08005268#elif defined(TARGET_ALPHA)
5269
5270struct target_sigcontext {
5271 abi_long sc_onstack;
5272 abi_long sc_mask;
5273 abi_long sc_pc;
5274 abi_long sc_ps;
5275 abi_long sc_regs[32];
5276 abi_long sc_ownedfp;
5277 abi_long sc_fpregs[32];
5278 abi_ulong sc_fpcr;
5279 abi_ulong sc_fp_control;
5280 abi_ulong sc_reserved1;
5281 abi_ulong sc_reserved2;
5282 abi_ulong sc_ssize;
5283 abi_ulong sc_sbase;
5284 abi_ulong sc_traparg_a0;
5285 abi_ulong sc_traparg_a1;
5286 abi_ulong sc_traparg_a2;
5287 abi_ulong sc_fp_trap_pc;
5288 abi_ulong sc_fp_trigger_sum;
5289 abi_ulong sc_fp_trigger_inst;
5290};
5291
5292struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005293 abi_ulong tuc_flags;
5294 abi_ulong tuc_link;
5295 abi_ulong tuc_osf_sigmask;
5296 target_stack_t tuc_stack;
5297 struct target_sigcontext tuc_mcontext;
5298 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005299};
5300
5301struct target_sigframe {
5302 struct target_sigcontext sc;
5303 unsigned int retcode[3];
5304};
5305
5306struct target_rt_sigframe {
5307 target_siginfo_t info;
5308 struct target_ucontext uc;
5309 unsigned int retcode[3];
5310};
5311
5312#define INSN_MOV_R30_R16 0x47fe0410
5313#define INSN_LDI_R0 0x201f0000
5314#define INSN_CALLSYS 0x00000083
5315
Riku Voipio41ecc722014-04-23 11:01:00 +03005316static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005317 abi_ulong frame_addr, target_sigset_t *set)
5318{
Riku Voipio41ecc722014-04-23 11:01:00 +03005319 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005320
Riku Voipio1d8b5122014-04-23 10:26:05 +03005321 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5322 __put_user(set->sig[0], &sc->sc_mask);
5323 __put_user(env->pc, &sc->sc_pc);
5324 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005325
5326 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005327 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005328 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005329 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005330
5331 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005332 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005333 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005334 __put_user(0, &sc->sc_fpregs[31]);
5335 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005336
Riku Voipio1d8b5122014-04-23 10:26:05 +03005337 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5338 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5339 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005340}
5341
Riku Voipio016d2e12014-04-23 11:19:48 +03005342static void restore_sigcontext(CPUAlphaState *env,
Andreas Färber05390242012-02-25 03:37:53 +01005343 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005344{
5345 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005346 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005347
Riku Voipio1d8b5122014-04-23 10:26:05 +03005348 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005349
5350 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005351 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005352 }
5353 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005354 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005355 }
5356
Riku Voipio1d8b5122014-04-23 10:26:05 +03005357 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005358 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005359}
5360
5361static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005362 CPUAlphaState *env,
5363 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005364{
5365 abi_ulong sp = env->ir[IR_SP];
5366
5367 /* This is the X/Open sanctioned signal stack switching. */
5368 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5369 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5370 }
5371 return (sp - framesize) & -32;
5372}
5373
5374static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005375 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005376{
5377 abi_ulong frame_addr, r26;
5378 struct target_sigframe *frame;
5379 int err = 0;
5380
5381 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005382 trace_user_setup_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005383 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5384 goto give_sigsegv;
5385 }
5386
Riku Voipio41ecc722014-04-23 11:01:00 +03005387 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005388
5389 if (ka->sa_restorer) {
5390 r26 = ka->sa_restorer;
5391 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005392 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5393 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5394 &frame->retcode[1]);
5395 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005396 /* imb() */
5397 r26 = frame_addr;
5398 }
5399
5400 unlock_user_struct(frame, frame_addr, 1);
5401
5402 if (err) {
5403 give_sigsegv:
5404 if (sig == TARGET_SIGSEGV) {
5405 ka->_sa_handler = TARGET_SIG_DFL;
5406 }
5407 force_sig(TARGET_SIGSEGV);
5408 }
5409
5410 env->ir[IR_RA] = r26;
5411 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5412 env->ir[IR_A0] = sig;
5413 env->ir[IR_A1] = 0;
5414 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5415 env->ir[IR_SP] = frame_addr;
5416}
5417
5418static void setup_rt_frame(int sig, struct target_sigaction *ka,
5419 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005420 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005421{
5422 abi_ulong frame_addr, r26;
5423 struct target_rt_sigframe *frame;
5424 int i, err = 0;
5425
5426 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005427 trace_user_setup_rt_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005428 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5429 goto give_sigsegv;
5430 }
5431
Peter Maydellf6c7a052015-01-08 12:19:48 +00005432 tswap_siginfo(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005433
Riku Voipio1d8b5122014-04-23 10:26:05 +03005434 __put_user(0, &frame->uc.tuc_flags);
5435 __put_user(0, &frame->uc.tuc_link);
5436 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5437 __put_user(target_sigaltstack_used.ss_sp,
5438 &frame->uc.tuc_stack.ss_sp);
5439 __put_user(sas_ss_flags(env->ir[IR_SP]),
5440 &frame->uc.tuc_stack.ss_flags);
5441 __put_user(target_sigaltstack_used.ss_size,
5442 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005443 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005444 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005445 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005446 }
5447
5448 if (ka->sa_restorer) {
5449 r26 = ka->sa_restorer;
5450 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005451 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5452 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5453 &frame->retcode[1]);
5454 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005455 /* imb(); */
5456 r26 = frame_addr;
5457 }
5458
5459 if (err) {
5460 give_sigsegv:
5461 if (sig == TARGET_SIGSEGV) {
5462 ka->_sa_handler = TARGET_SIG_DFL;
5463 }
5464 force_sig(TARGET_SIGSEGV);
5465 }
5466
5467 env->ir[IR_RA] = r26;
5468 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5469 env->ir[IR_A0] = sig;
5470 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5471 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5472 env->ir[IR_SP] = frame_addr;
5473}
5474
Andreas Färber05390242012-02-25 03:37:53 +01005475long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005476{
5477 struct target_sigcontext *sc;
5478 abi_ulong sc_addr = env->ir[IR_A0];
5479 target_sigset_t target_set;
5480 sigset_t set;
5481
5482 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5483 goto badframe;
5484 }
5485
5486 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005487 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005488
5489 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005490 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005491
Riku Voipio016d2e12014-04-23 11:19:48 +03005492 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005493 unlock_user_struct(sc, sc_addr, 0);
5494 return env->ir[IR_V0];
5495
5496 badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005497 force_sig(TARGET_SIGSEGV);
5498}
5499
Andreas Färber05390242012-02-25 03:37:53 +01005500long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005501{
5502 abi_ulong frame_addr = env->ir[IR_A0];
5503 struct target_rt_sigframe *frame;
5504 sigset_t set;
5505
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005506 trace_user_do_rt_sigreturn(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005507 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5508 goto badframe;
5509 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005510 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005511 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005512
Riku Voipio016d2e12014-04-23 11:19:48 +03005513 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005514 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005515 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005516 0, env->ir[IR_SP]) == -EFAULT) {
5517 goto badframe;
5518 }
5519
5520 unlock_user_struct(frame, frame_addr, 0);
5521 return env->ir[IR_V0];
5522
5523
5524 badframe:
5525 unlock_user_struct(frame, frame_addr, 0);
5526 force_sig(TARGET_SIGSEGV);
5527}
5528
Chen Gangbf0f60a2015-09-27 08:10:18 +08005529#elif defined(TARGET_TILEGX)
5530
5531struct target_sigcontext {
5532 union {
5533 /* General-purpose registers. */
5534 abi_ulong gregs[56];
5535 struct {
5536 abi_ulong __gregs[53];
5537 abi_ulong tp; /* Aliases gregs[TREG_TP]. */
5538 abi_ulong sp; /* Aliases gregs[TREG_SP]. */
5539 abi_ulong lr; /* Aliases gregs[TREG_LR]. */
5540 };
5541 };
5542 abi_ulong pc; /* Program counter. */
5543 abi_ulong ics; /* In Interrupt Critical Section? */
5544 abi_ulong faultnum; /* Fault number. */
5545 abi_ulong pad[5];
5546};
5547
5548struct target_ucontext {
5549 abi_ulong tuc_flags;
5550 abi_ulong tuc_link;
5551 target_stack_t tuc_stack;
5552 struct target_sigcontext tuc_mcontext;
5553 target_sigset_t tuc_sigmask; /* mask last for extensibility */
5554};
5555
5556struct target_rt_sigframe {
5557 unsigned char save_area[16]; /* caller save area */
5558 struct target_siginfo info;
5559 struct target_ucontext uc;
5560};
5561
5562static void setup_sigcontext(struct target_sigcontext *sc,
5563 CPUArchState *env, int signo)
5564{
5565 int i;
5566
5567 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5568 __put_user(env->regs[i], &sc->gregs[i]);
5569 }
5570
5571 __put_user(env->pc, &sc->pc);
5572 __put_user(0, &sc->ics);
5573 __put_user(signo, &sc->faultnum);
5574}
5575
5576static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
5577{
5578 int i;
5579
5580 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5581 __get_user(env->regs[i], &sc->gregs[i]);
5582 }
5583
5584 __get_user(env->pc, &sc->pc);
5585}
5586
5587static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
5588 size_t frame_size)
5589{
5590 unsigned long sp = env->regs[TILEGX_R_SP];
5591
5592 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
5593 return -1UL;
5594 }
5595
5596 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
5597 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5598 }
5599
5600 sp -= frame_size;
5601 sp &= -16UL;
5602 return sp;
5603}
5604
5605static void setup_rt_frame(int sig, struct target_sigaction *ka,
5606 target_siginfo_t *info,
5607 target_sigset_t *set, CPUArchState *env)
5608{
5609 abi_ulong frame_addr;
5610 struct target_rt_sigframe *frame;
5611 unsigned long restorer;
5612
5613 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005614 trace_user_setup_rt_frame(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005615 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5616 goto give_sigsegv;
5617 }
5618
5619 /* Always write at least the signal number for the stack backtracer. */
5620 if (ka->sa_flags & TARGET_SA_SIGINFO) {
5621 /* At sigreturn time, restore the callee-save registers too. */
5622 tswap_siginfo(&frame->info, info);
5623 /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
5624 } else {
5625 __put_user(info->si_signo, &frame->info.si_signo);
5626 }
5627
5628 /* Create the ucontext. */
5629 __put_user(0, &frame->uc.tuc_flags);
5630 __put_user(0, &frame->uc.tuc_link);
5631 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
5632 __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
5633 &frame->uc.tuc_stack.ss_flags);
5634 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
5635 setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
5636
5637 restorer = (unsigned long) do_rt_sigreturn;
5638 if (ka->sa_flags & TARGET_SA_RESTORER) {
5639 restorer = (unsigned long) ka->sa_restorer;
5640 }
5641 env->pc = (unsigned long) ka->_sa_handler;
5642 env->regs[TILEGX_R_SP] = (unsigned long) frame;
5643 env->regs[TILEGX_R_LR] = restorer;
5644 env->regs[0] = (unsigned long) sig;
5645 env->regs[1] = (unsigned long) &frame->info;
5646 env->regs[2] = (unsigned long) &frame->uc;
5647 /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
5648
5649 unlock_user_struct(frame, frame_addr, 1);
5650 return;
5651
5652give_sigsegv:
5653 if (sig == TARGET_SIGSEGV) {
5654 ka->_sa_handler = TARGET_SIG_DFL;
5655 }
5656 force_sig(TARGET_SIGSEGV /* , current */);
5657}
5658
5659long do_rt_sigreturn(CPUTLGState *env)
5660{
5661 abi_ulong frame_addr = env->regs[TILEGX_R_SP];
5662 struct target_rt_sigframe *frame;
5663 sigset_t set;
5664
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005665 trace_user_do_rt_sigreturn(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005666 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5667 goto badframe;
5668 }
5669 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
5670 do_sigprocmask(SIG_SETMASK, &set, NULL);
5671
5672 restore_sigcontext(env, &frame->uc.tuc_mcontext);
5673 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
5674 uc.tuc_stack),
5675 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
5676 goto badframe;
5677 }
5678
5679 unlock_user_struct(frame, frame_addr, 0);
5680 return env->regs[TILEGX_R_RE];
5681
5682
5683 badframe:
5684 unlock_user_struct(frame, frame_addr, 0);
5685 force_sig(TARGET_SIGSEGV);
5686}
5687
bellardb346ff42003-06-15 20:05:50 +00005688#else
5689
pbrook624f7972008-05-31 16:11:38 +00005690static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005691 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005692{
5693 fprintf(stderr, "setup_frame: not implemented\n");
5694}
5695
pbrook624f7972008-05-31 16:11:38 +00005696static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005697 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005698 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005699{
5700 fprintf(stderr, "setup_rt_frame: not implemented\n");
5701}
5702
Andreas Färber9349b4f2012-03-14 01:38:32 +01005703long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005704{
5705 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005706 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005707}
5708
Andreas Färber9349b4f2012-03-14 01:38:32 +01005709long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005710{
5711 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005712 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005713}
5714
bellard66fb9762003-03-23 01:06:05 +00005715#endif
5716
Andreas Färber9349b4f2012-03-14 01:38:32 +01005717void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005718{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005719 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005720 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005721 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005722 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005723 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005724 struct emulated_sigtable *k;
5725 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005726 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005727 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005728
pbrook624f7972008-05-31 16:11:38 +00005729 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005730 return;
5731
pbrook624f7972008-05-31 16:11:38 +00005732 /* FIXME: This is not threadsafe. */
5733 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005734 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5735 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005736 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005737 k++;
bellard31e31b82003-02-18 22:55:36 +00005738 }
5739 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005740 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005741 return;
bellard66fb9762003-03-23 01:06:05 +00005742
bellard31e31b82003-02-18 22:55:36 +00005743 handle_signal:
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005744 trace_user_handle_signal(cpu_env, sig);
bellard66fb9762003-03-23 01:06:05 +00005745 /* dequeue signal */
5746 q = k->first;
5747 k->first = q->next;
5748 if (!k->first)
5749 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005750
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005751 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005752 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005753 sa = NULL;
5754 handler = TARGET_SIG_IGN;
5755 } else {
5756 sa = &sigact_table[sig - 1];
5757 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005758 }
bellard66fb9762003-03-23 01:06:05 +00005759
Peter Maydella7ec0f92014-03-14 14:36:56 +00005760 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5761 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5762 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5763 * because it got a real MMU fault), and treat as if default handler.
5764 */
5765 handler = TARGET_SIG_DFL;
5766 }
5767
bellard66fb9762003-03-23 01:06:05 +00005768 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005769 /* default handler : ignore some signal. The other are job control or fatal */
5770 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5771 kill(getpid(),SIGSTOP);
5772 } else if (sig != TARGET_SIGCHLD &&
5773 sig != TARGET_SIGURG &&
5774 sig != TARGET_SIGWINCH &&
5775 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005776 force_sig(sig);
5777 }
5778 } else if (handler == TARGET_SIG_IGN) {
5779 /* ignore sig */
5780 } else if (handler == TARGET_SIG_ERR) {
5781 force_sig(sig);
5782 } else {
bellard9de5e442003-03-23 16:49:39 +00005783 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005784 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005785 /* SA_NODEFER indicates that the current signal should not be
5786 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005787 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005788 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005789
bellard9de5e442003-03-23 16:49:39 +00005790 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005791 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005792 /* save the previous blocked signal state to restore it at the
5793 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005794 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005795
bellardbc8a22c2003-03-30 21:02:40 +00005796 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005797#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005798 {
5799 CPUX86State *env = cpu_env;
5800 if (env->eflags & VM_MASK)
5801 save_v86_state(env);
5802 }
5803#endif
bellard9de5e442003-03-23 16:49:39 +00005804 /* prepare the stack frame of the virtual CPU */
Chen Gangd0924a22015-09-12 23:32:30 +08005805#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
Chen Gangbf0f60a2015-09-27 08:10:18 +08005806 || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)
Richard Hendersonff970902013-02-10 10:30:42 -08005807 /* These targets do not have traditional signals. */
5808 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5809#else
pbrook624f7972008-05-31 16:11:38 +00005810 if (sa->sa_flags & TARGET_SA_SIGINFO)
5811 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005812 else
pbrook624f7972008-05-31 16:11:38 +00005813 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005814#endif
pbrook624f7972008-05-31 16:11:38 +00005815 if (sa->sa_flags & TARGET_SA_RESETHAND)
5816 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005817 }
bellard66fb9762003-03-23 01:06:05 +00005818 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005819 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005820}